1. NVIDIA GPUDirect Storage 安装和故障排除指南#

本指南介绍了如何安装、调试和隔离与 GDS 相关的性能和功能问题,适用于系统管理员和开发人员。

2. 简介#

本指南介绍了如何调试和隔离与 NVIDIA® Magnum IO GPUDirect® Storage (GDS) 相关的性能和功能问题,适用于系统管理员和开发人员。

GDS 为 GPU 内存和存储之间的直接内存访问 (DMA) 传输启用直接数据路径,从而避免了通过 CPU 的反弹缓冲区。此直接路径增加了系统带宽,并降低了 CPU 的延迟和利用率负载。

创建此直接路径涉及分布式文件系统,例如 NFSoRDMA、DDN EXAScaler 并行文件系统解决方案(基于 Lustre 文件系统)和 WekaFS,因此 GDS 环境由多个软件和硬件组件组成。本指南解决了与 GDS 安装相关的问题,并帮助您诊断功能和性能问题。对于非 GDS 问题,请联系相应的 OEM 或文件系统供应商以了解和调试问题。

3. 安装 GPUDirect Storage#

本节包括 GDS 安装、卸载、配置信息以及使用实验性存储库。

注意

对于 NVAIE 和 vGPU 环境,请按照各自文档中的步骤操作。

3.1. 安装 GDS 之前#

要在非 DGX 平台上安装 GDS,请完成以下步骤

  1. 运行以下命令以检查 IOMMU 的当前状态。

    $ dmesg | grep -i iommu
    

    在基于 x86_64 的平台上,如果 IOMMU 为启用状态,请完成步骤 2 以禁用它,否则继续执行步骤 3。

  2. 禁用 IOMMU。

    注意

    根据我们的经验,iommu=off 在功能和性能方面效果最佳。在某些平台(例如 DGX A100 和 DGX-2)上,支持 iommu=ptiommu=on 不能保证在功能上或性能上都能正常工作。

    运行以下命令

     $ sudo vi /etc/default/grub
    
     b. Add one of the following options to the ``GRUB_CMDLINE_LINUX_DEFAULT`` option.
    
       - If you have an **AMD** CPU, add ``amd_iommu=off``.
       - If you have an **Intel** CPU, add ``intel_iommu=off``.
    
       If there are already other options, enter a space to separate the options, for example,
       ``GRUB_CMDLINE_LINUX_DEFAULT="console=tty0 amd_iommu=off``
    
     c. Run the following commands:
    
        $ sudo update-grub
        $ sudo reboot
    
    d. After the system reboots, to verify that the change took effect, run the following command:
    
    $ cat /proc/cmdline
    
       It should show the options which have been added to the grub file.
    

    在按照说明操作之前,请阅读“注意”部分。

    使用 MLNX_OFED 要求和安装 安装 MLNX_OFED 或 DOCA 要求和安装 安装 DOCA。

    注意

    • 只有当您需要启用对 NVMe、NVMf、NFSoRDMA 的支持时,才需要执行此步骤

    • 对于 DGX OS 6.x 或更高版本,不需要执行此步骤。

3.2. 安装 GDS#

GDS 安装支持两种方式

  • 使用软件包管理器,例如 Debian 和 RPM

有关在 DGX 平台上安装的信息,请参阅

有关在非 DGX 平台上安装的信息,请参阅此处

注意

对于 CUDA 11.5.1 及更高版本,如果您计划使用 Weka FS 或 IBM SpectrumScale,则必须运行

modprobe nvidia_peermem

这将加载支持 PeerDirect 功能的模块。系统重启后必须运行此命令。

为了在每次重启后自动加载模块,请运行以下命令

echo "nvidia-peermem" | sudo tee /etc/modules-load.d/nvidia-peermem.conf

在本文档中,cuda-<x>.<y> 中,x 指的是 CUDA 主要版本,y 指的是次要版本。

3.2.1. 配置 GDS 的文件系统设置#

在继续之前,请参阅本文档中特定于文件系统的部分,了解支持 GDS 所需的必要配置

注意

对于本地文件系统(例如 Ext4/XFS),可以跳过此步骤。

3.2.2. 验证 GDS 安装是否成功#

要验证 GDS 安装是否成功,请运行 gdscheck

$ /usr/local/cuda-<x>.<y>/gds/tools/gdscheck.py -p

注意

gdscheck 命令需要系统上存在 python3。如果由于 python3 不可用而失败,则可以使用 python(即 python2)的安装路径显式调用该命令。例如

$ /usr/bin/python /usr/local/cuda-<x>.<y>/gds/tools/gdscheck.py -p

此命令的输出显示系统上安装的受支持文件系统或设备是否支持 GDS。输出还显示是否在任何 PCI 交换机上启用了 PCIe ACS。

注意

为了获得最佳 GDS 性能,请禁用 PCIe ACS。

示例输出

GDS release version: 1.13.0.7
 nvidia_fs version:  2.24 libcufile version: 2.12
 Platform: x86_64
 ============
 ENVIRONMENT:
 ============
 =====================
 DRIVER CONFIGURATION:
 =====================
 NVMe P2PDMA        : Supported
 NVMe               : Supported
 NVMeOF             : Unsupported
 SCSI               : Unsupported
 ScaleFlux CSD      : Unsupported
 NVMesh             : Unsupported
 DDN EXAScaler      : Supported
 IBM Spectrum Scale : Unsupported
 NFS                : Unsupported
 BeeGFS             : Unsupported
 WekaFS             : Supported
 Userspace RDMA     : Supported
 --Mellanox PeerDirect : Enabled
 --DmaBuf support : Enabled
 --rdma library        : Loaded (libcufile_rdma.so)
 --rdma devices        : Configured
 --rdma_device_status  : Up: 1 Down: 0
 =====================
 CUFILE CONFIGURATION:
 =====================
 properties.use_pci_p2pdma : true
 properties.use_compat_mode : true
 properties.force_compat_mode : false
 properties.gds_rdma_write_support : true
 properties.use_poll_mode : false
 properties.poll_mode_max_size_kb : 4
 properties.max_batch_io_size : 128
 properties.max_batch_io_timeout_msecs : 5
 properties.max_direct_io_size_kb : 16384
 properties.max_device_cache_size_kb : 131072
 properties.max_device_pinned_mem_size_kb : 33554432
 properties.posix_pool_slab_size_kb : 4 1024 16384
 properties.posix_pool_slab_count : 128 64 64
 properties.rdma_peer_affinity_policy : RoundRobin
 properties.rdma_dynamic_routing : 0
 fs.generic.posix_unaligned_writes : false
 fs.lustre.posix_gds_min_kb: 0
 fs.beegfs.posix_gds_min_kb: 0
 fs.weka.rdma_write_support: false
 fs.gpfs.gds_write_support: false
 fs.gpfs.gds_async_support: true
 profile.nvtx : false
 profile.cufile_stats : 2
 miscellaneous.api_check_aggressive : false
 execution.max_io_threads : 0
 execution.max_io_queue_depth : 128
 execution.parallel_io : false
 execution.min_io_threshold_size_kb : 8192
 execution.max_request_parallelism : 4
 properties.force_odirect_mode : false
 properties.prefer_iouring : false
 =========
 GPU INFO:
 =========
 GPU index 0 NVIDIA L4 bar:1 bar size (MiB):32768 supports GDS, IOMMU State: Disabled
 ==============
 PLATFORM INFO:
 ==============
 IOMMU: disabled
 Nvidia Driver Info Status: Supported(Nvidia Open Driver Installed)
 Cuda Driver Version Installed:  12080
 Platform: ProLiant DL360 Gen10, Arch: x86_64(Linux 6.8.0-31-generic)
 Platform verification succeeded

注意

/usr/local/cuda-<x>.<y>/gds/tools/usr/local/cuda-<x>.<y>/gds/samples 中提供了 README,以显示用法。

3.3. 已安装的 GDS 库和工具#

GPUDirect Storage 用户空间库位于 /usr/local/cuda-<X>.<Y>/targets/x86_64-linux/lib/ 目录中。

注意

GPUDirect Storage 软件包安装在 /usr/local/cuda-X.Y/gds 中,其中 X 是 CUDA 工具包的主要版本,Y 是次要版本。

$ ls -1 /usr/local/cuda-X.Y/targets/x86_64-linux/lib/*cufile*
cufile.h
libcufile.so
libcufile.so.0
libcufile.so.1.0.0
libcufile_rdma.so
libcufile_rdma.so.0
libcufile_rdma.so.1.0.0

GPUDirect Storage 工具和示例位于 /usr/local/cuda-X.Y/gds 目录中。

$ ls -lh /usr/local/cuda-X.Y/gds/
total 20K
-rw-r--r-- 1 root root 8.4K Mar 15 13:01 README
drwxr-xr-x 2 root root 4.0K Mar 19 12:29 samples
drwxr-xr-x 2 root root 4.0K mar 19 10:28 tools

对于此版本,GPUDirect Storage 提供了额外的 libcufile-dev 软件包(cuFile 库开发人员软件包)。这主要用于开发人员环境。本质上,lincufile-dev 软件包包含 cuFile 库的静态版本(libcufile_static.alibcufile_rdma_static.a)和 cufile.h 头文件,使用 cuFile 库 API 的应用程序可能需要这些文件。

3.4. 卸载 GPUDirect Storage#

要从 Ubuntu 和 DGX OS 卸载 GDS

$ sudo apt-get remove --purge "*libcufile*" "*gds-tools*" "*nvidia-fs*"

要从 RHEL 卸载

$ sudo dnf remove "nvidia-gds*"

3.5. GPUDirect Storage 使用的环境变量#

GDS 使用以下环境变量。

表 1 GDS 环境变量#

CUFILE_ENV 变量

描述

CUFILE_CQ_DEPTH

DC 目标的完成队列深度。

CUFILE_ENV_EXPERIMENTAL_FS=1

控制 cufile 是否检查受支持的文件系统。设置为 1 时,允许使用尚未正式启用 cuFile 的新文件系统进行测试。

CUFILE_ENV_PATH_JSON=/home/user/cufile.json

控制 cuFile 库从中读取配置变量的路径。这可以用于容器环境和需要与 /etc/cufile.json 中的系统默认配置不同的配置设置的应用程序。

CUFILE_ETH_SL

为用户空间 RDMA 目标(WekaFS 和 GPFS)在 RoCEv2 设备 QP 上设置 QOS 级别。

CUFILE_IB_SL=\[0-15\]

为用户空间 RDMA 目标(WekaFS 和 GPFS)在 IB 设备 QP 上设置 QOS 级别。

CUFILE_LOGFILE_PATH=/etc/log/cufile_\$\$.log

控制 cuFile 日志信息的路径。指定默认日志路径,即应用程序的当前工作目录。对容器或日志记录很有用。

CUFILE_LOGGING_LEVEL=TRACE

控制跟踪级别,并且可以覆盖特定应用程序的跟踪级别,而无需新的配置文件。

CUFILE_MIN_RNR_TIMER

QP 的最小 RNR 值,在此值之后,如果远程端没有发布工作请求,QP 将因 RNR 超时而报错。默认值为 16 (2.56ms)。

CUFILE_NVTX=true

启用 NVTX 跟踪以用于 Nsight 系统。

CUFILE_RDMA_DC_KEY="0XABABCDEF"

为 WekaFS 和 GPFS 的用户空间 RDMA DC 目标控制 DC_KEY。

CUFILE_RDMA_HOP_LIMIT

数据包在网络上被丢弃之前的最大跳数。防止数据包无限循环。默认值为 64。

CUFILE_RDMA_PKEY_INDEX

分区密钥索引。

CUFILE_RDMA_SR_MAX_WR

共享请求队列支持的最大工作请求数。

CUFILE_RDMA_SR_MAX_SGE

每个工作请求支持的最大分散聚集条目数。

CUFILE_SKIP_TOPOLOGY_DETECTION

将此环境变量设置为 true 将跳过兼容模式下的拓扑检测。这将减少在具有多个 PCI 设备的系统上兼容模式下出现的高启动延迟。

CUFILE_FORCE_COMPAT_MODE

覆盖 cufile.json 设置,并强制 I/O 通过兼容模式而不是 GDS 模式。

CUFILE_ALLOW_COMPAT_MODE

这与 cufile.json 文件中的 allow_compat_mode 标记的作用完全相同。

CUFILE_USE_PCIP2PDMA

设置为 true 时,如果内核支持,则 IO 首选项将设置为 NVMe 的 PCI p2pdma 路径,而不是传统的 nvidia-fs 路径,否则将使用通过 nvidia-fs 的传统路径。

3.6. GPUDirect Storage 使用的 JSON 配置参数#

有关 GDS 使用的 JSON 配置参数的详细信息,请参阅GPUDirect Storage 参数

对于尚未设置 GDS 支持的系统或挂载,请考虑 compat_mode。要了解有关兼容模式的更多信息,请参阅cuFile 兼容模式

3.7. 支持动态路由的 GDS 配置文件更改#

为了使动态路由支持多个文件系统和挂载点,请为单个挂载配置全局的每个文件系统 rdma_dev_addr_list 属性,或为每个文件系统挂载表配置 rdma_dev_addr_list 属性。

"fs": {
      "lustre": {
      // if using a single lustre mount, provide the ip addresses
      // here (use : sudo lnetctl net show)
      //"rdma_dev_addr_list" : []

      // if using multiple lustre mounts, provide ip addresses
      // used by respective mount here
      //"mount_table" : {
      // "/lustre/ai200_01/client" : {
      //    "rdma_dev_addr_list" : ["172.172.1.40",
                          "172.172.1.42"]
      // },

      // "/lustre/ai200_02/client" : {
      //    "rdma_dev_addr_list" : ["172.172.2.40",
                          "172.172.2.42"]
      //}
     },

     "nfs": {
        //"rdma_dev_addr_list" : []

        //"mount_table" : {
        //  "/mnt/nfsrdma_01/" : {
        //           "rdma_dev_addr_list" : []
        //},

        //  "/mnt/nfsrdma_02/" : {
        //           "rdma_dev_addr_list" : []
        //}
        //}
        },
     },

3.8. 确定安装了哪个版本的 GDS#

要确定您拥有的 GDS 版本,请运行以下命令

$ gdscheck.py -v

示例输出

GDS release version: 1.0.0.78
 nvidia_fs version:  2.7 libcufile version: 2.4

3.9. 用于 DGX 系统 GDS 软件包网络安装的实验性存储库#

可以通过在受支持的 DGX 平台上使用以下步骤启用预览存储库来安装 GDS 1.0.0 和 MLNX_OFED 软件包。

对于 Ubuntu 18.04/20.04 发行版

可以通过网络使用预览网络存储库安装 GDS 1.0.0、NVSM 和 MLNX_OFED 软件包。

对于 Ubuntu 20.04 发行版

$ sudo apt-key adv --fetch-keys https://repo.download.nvidia.com/baseos/GPG-KEY-dgx-cosmos-support

$ sudo add-apt-repository "deb https://repo.download.nvidia.com/baseos/ubuntu/focal/x86_64/ focal-updates preview"

$ sudo apt update

4. API 错误#

本节提供有关使用 GDS 时可能遇到的常见 API 错误的信息。

4.1. CU_FILE_DRIVER_NOT_INITIALIZED#

如果未调用 cuFileDriverOpen API,则在隐式调用驱动程序初始化时遇到的错误将报告为在调用 cuFileBufRegistercuFileHandleRegister 时遇到的 cuFile 错误。

4.2. CU_FILE_DEVICE_NOT_SUPPORTED#

GDS 仅在支持计算模式的 NVIDIA 图形处理器 (GPU) Tesla® 或 Quadro® 型号以及计算主要能力大于或等于 6 的型号上受支持。

注意

这包括 V100 和 T4 卡。

4.3. CU_FILE_IO_NOT_SUPPORTED#

如果文件描述符来自本地文件系统,或者来自未准备好 GDS 的挂载,则 API 返回 CU_FILE_IO_NOT_SUPPORTED 错误。

有关受支持文件系统的列表,请参阅安装 GDS 之前

此错误的常见原因包括

  • 文件描述符属于不受支持的文件系统。

  • 指定的 fd 不是常规 UNIX 文件。

  • fd 上设置了加密和压缩、合规性设置的任意组合。

    例如,FS_COMPR_FL | FS_ENCRYPT_FL | FS_APPEND_FL | FS_IMMUTABLE_FL

    注意

    compat_mode 设置为 true 时,允许使用这些设置。

  • fd 的打开调用中指定了不受支持的文件模式的任意组合。例如,

    O_APPEND | O_NOCTTY | O_NONBLOCK | O_DIRECTORY | O_NOFOLLOW | O_TMPFILE
    

4.4. CU_FILE_CUDA_MEMORY_TYPE_INVALID#

cudaMallocManaged 内存的物理内存是在首次使用时动态分配的。目前,它不提供公开物理内存或基址寄存器 (BAR) 内存以供 GDS 使用的机制。但是,当内存用作 cuFileWritecuFileRead 的未注册缓冲区时,GDS 间接支持 cudaMallocManaged 内存。

5. 基本故障排除#

5.1. GDS 库的日志文件#

cufile.log 文件在应用程序二进制文件所在的同一位置创建。当前,最大日志文件大小为 32MB。如果日志文件大小增加到大于 32MB,则日志文件将被截断,并且日志记录将在同一文件上恢复。

5.2. 为每个应用程序启用不同的 cufile.log 文件#

您可以为每个应用程序启用不同的 cufile.log 文件。

有几个相关的情况

  • 如果默认 /etc/cufile.json 文件中的 logging:dir 属性未设置,则默认情况下,cufile.log 文件在应用程序的当前工作目录中生成。

  • 如果在默认 /etc/cufile.json 文件中设置了 logging:dir 属性,则日志文件将在指定的目录路径中创建。

注意

对于多个应用程序使用 libcufile.so 库的场景,通常不建议这样做。

例如

"logging": {
    // log directory, if not enabled
    // will create log file under current working
    // directory
      "dir": "/opt/gdslogs/",
}

cufile.log 将创建为 /opt/gdslogs/cufile.log 文件。

如果应用程序需要为不同的应用程序启用不同的 cufile.log,则应用程序可以通过执行以下步骤来覆盖默认 JSON 路径

  1. 导出 CUFILE_ENV_PATH_JSON=”/opt/myapp/cufile.json”。

  2. 编辑 /opt/myapp/cufile.json 文件。

    "logging": {
        // log directory, if not enabled
        // will create log file under current working
        // directory
        "dir": "/opt/myapp",
    }
    
  3. 运行应用程序。

  4. 要检查日志,请运行

    $ ls -l /opt/myapp/cufile.log
    

5.3. 启用跟踪 GDS 库 API 调用#

有不同的日志记录级别,可以在 /etc/cufile.json 文件中启用。

默认情况下,日志记录级别设置为 ERROR。随着我们增加详细级别(如 INFODEBUGTRACE),日志记录将对性能产生影响,应仅在调试现场问题时启用。

配置跟踪并运行以下命令

"logging": {
    // log directory, if not enabled
    // will create log file under local directory
    //"dir": "/home/<xxxx>",
    // ERROR|WARN|INFO|DEBUG|TRACE (in decreasing order of priority)
    "level": "ERROR"
},

5.4. cuFileHandleRegister 错误#

如果在发出 IO 时在 cufile.log 文件中看到 cuFileHandleRegister 错误

"cuFileHandleRegister error: GPUDirect Storage not supported on current file."

以下是可能发生此错误的一些原因

  • GDS 不支持该文件系统。

    有关详细信息,请参阅CU_FILE_DEVICE_NOT_SUPPORTED

  • DIRECT_IO 功能不受文件所在挂载点的支持。

有关更多信息,请在 /etc/cufile.json 文件中启用跟踪。

5.5. 排除返回 cuFile 错误的应用程序的故障#

要排除 cuFile 错误,请执行以下操作

  1. 有关 API 返回的错误的更多信息,请参阅 cufile.h 文件。

  2. 如果 IO 已提交到 GDS 驱动程序,请检查 GDS 统计信息中是否有任何错误。

    如果 IO 失败,则错误统计信息应提供有关错误类型的信息。

    有关更多信息,请参阅查找 GDS 驱动程序统计信息

  3. 启用 GDS 库跟踪并监控 cufile.log 文件。

  4. 启用 GDS 驱动程序调试

    $ echo 1 >/sys/module/nvidia_fs/parameters/dbg_enabled
    

启用驱动程序调试日志后,您可能会获得有关错误的更多信息。

5.6. cuFile-* 错误,GPUDirect Storage 统计信息中无活动#

如果 GDS 统计信息中存在 cuFile 错误,则表示 API 在 GDS 库中失败。您可以通过在 /etc/cufile.json 文件中设置适当的日志记录级别来启用跟踪,以获取有关 cufile.log 中故障的更多信息。

5.7. CUDA 运行时和驱动程序不匹配,错误代码为 35#

CUDA 文档中的错误代码 35 指向 cudaErrorInsufficientDriver,这表示已安装的 NVIDIA CUDA 驱动程序比 CUDA 运行时库旧。这是不受支持的配置。要使应用程序运行,您必须更新 NVIDIA 显示驱动程序。

注意

cuFile 工具依赖于 CUDA 运行时 10.1 及更高版本。您必须确保安装的 CUDA 运行时与安装的 CUDA 驱动程序兼容,并且是推荐的版本。

5.8. 运行 cuFile-* API 时出现 CUDA API 错误#

GDS 库使用 CUDA 驱动程序 API。

如果您观察到 CUDA API 错误,您将观察到错误代码。有关更多信息,请参阅CUDA 库文档中的错误代码。

5.9. 查找 GDS 驱动程序统计信息#

要查找 GDS 驱动程序统计信息,请运行以下命令

$ cat /proc/driver/nvidia-fs/stats

GDS 驱动程序内核统计信息 READ / WRITE 适用于除 Weka 之外的所有文件系统。对于 Weka 文件系统统计信息,有关 READ / WRITE 的更多信息,请参阅WekaIO 文件系统的故障排除和常见问题解答

5.10. 跟踪通过 GDS 驱动程序的 IO 活动#

在 GDS 驱动程序统计信息中,“ops”行显示活动 IO 操作。ReadWrite 字段显示当前正在进行的活动操作。此信息应提供有关内核中所有应用程序正在进行的 IO 总数的概念。如果用户空间中存在瓶颈,则活动 IO 的数量将少于提交 IO 的线程数。此外,要获得有关 ReadWrite 带宽数字的更多详细信息,请查找 Read/Write 行中的计数器。

5.11. GDS 统计信息中的读取/写入带宽和延迟数字#

测量的延迟从提交 IO 时开始,到 GDS 内核驱动程序收到 IO 完成时结束。不报告用户空间延迟。这应提供有关用户空间是否受瓶颈限制或 IO 是否受后端磁盘/光纤通道瓶颈限制的概念。

注意

WekaIO 文件系统读取不通过 nvidia-fs 驱动程序,因此通过此接口,Read/Write 带宽统计信息不适用于 WekaIO 文件系统。

有关更多信息,请参阅WekaIO 文件系统的故障排除和常见问题解答

5.12. 跟踪 GPU 缓冲区的注册和注销#

在 GDS 驱动程序统计信息中,查找 BAR1-map 统计信息行中的活动字段。

通过 cuFileBufRegistercuFileBufDeregister 固定和取消固定 GPU 内存是一项开销很大的操作。如果您注意到 nvidia-fs 统计信息中有大量的 registrations(n)deregistration(free),则可能会损害性能。有关使用 cuFileBufRegister API 的更多信息,请参阅GPUDirect Storage 最佳实践指南

5.13. 为用户空间文件系统启用特定于 RDMA 的日志记录#

为了排除用户空间文件系统的 RDMA 相关问题,请确保在运行应用程序之前将 CUFILE_LOGGING_LEVEL 环境变量设置为 INFODEBUGTRACE。但是,为了使此操作生效,cufile.json 日志记录级别也应设置为 TRACE/DEBUG/INFO 级别。

例如

$ export CUFILE_LOGGING_LEVEL=INFO
  This is an example to set log level to INFO via the environment variable.

$ cat /etc/cufile.json
   ....
   "logging": {
        // log directory, if not enabled will create log file
        // under current working directory
        //"dir": "/home/<xxxx>",
        // ERROR|WARN|INFO|DEBUG|TRACE (in decreasing order of priority)
        "level": "DEBUG"
   },
   ....
   This is an example on how to set log level to DEBUG via cufile.json.

5.14. 安装后出现 CUDA_ERROR_SYSTEM_NOT_READY#

在具有 NVSwitch 的系统上,如果您注意到报告了 CUDA_ERROR_SYSTEM_NOT_READY 错误,请确保安装与 CUDA 驱动程序相同版本的 Fabric Manager。

例如,如果您使用

$ sudo apt install nvidia-driver-460-server -y

然后使用

$ apt-get install nvidia-fabricmanager-460

确保使用以下命令重启 Fabric Manager 服务

$ sudo service nvidia-fabricmanager start

5.15. 为 RAID 卷添加 udev 规则#

要为 RAID 卷添加 udev 规则

以 sudo 用户身份,更改 /lib/udev/rules.d/63-md-raid-arrays.rules 中的以下行

IMPORT{program}="/usr/sbin/mdadm --detail --export $devnode"

重启节点或重启 mdadm

5.16. 当您在 NVME 驱动器上观察到“写入不完整”时#

在 GDS 模式写入期间,您可能会收到类似于以下的错误消息

Tid: 0 incomplete Write, done = 0 issued = 1048576

P2P 模式下的 GPUDirect Storage 不支持 NVMe 端到端数据保护功能。要在 P2P 模式下支持 GDS,NVMe 必须使用保护信息格式化 - Metadata Size 设置为零字节。

确认驱动器已启用数据完整性模式

$ sudo nvme id-ns /dev/nvme0n1 -H
-
LBA Format  0 : Metadata Size: 0   bytes - Data Size: 512 bytes - Relative Performance: 0x1 Better
LBA Format  1 : Metadata Size: 8   bytes - Data Size: 512 bytes - Relative Performance: 0x3 Degraded (in use)
LBA Format  2 : Metadata Size: 0   bytes - Data Size: 4096 bytes - Relative Performance: 0 Best
LBA Format  3 : Metadata Size: 8   bytes - Data Size: 4096 bytes - Relative Performance: 0x2 Good
LBA Format  4 : Metadata Size: 64  bytes - Data Size: 4096 bytes - Relative Performance: 0x3 Degraded

请注意,在前面的示例中,驱动器 (nvme0n1) 的元数据大小设置为非零。

您可以将 LBA 格式设置为 0 或 2 以禁用驱动器上的保护功能

$ sudo nvme format /dev/nvme0n1 -l 2
$ sudo nvme id-ns /dev/nvme0n1 -H
-
LBA Format  0 : Metadata Size: 0   bytes - Data Size: 512 bytes - Relative Performance: 0x1 Better
LBA Format  1 : Metadata Size: 8   bytes - Data Size: 512 bytes - Relative Performance: 0x3 Degraded
LBA Format  2 : Metadata Size: 0   bytes - Data Size: 4096 bytes - Relative Performance: 0 Best (in use)
LBA Format  3 : Metadata Size: 8   bytes - Data Size: 4096 bytes - Relative Performance: 0x2 Good
LBA Format  4 : Metadata Size: 64  bytes - Data Size: 4096 bytes - Relative Performance: 0x3 Degraded

5.17. CUFILE 异步 I/O 失败#

基于流的异步 I/O 失败可能有多种原因。这将记录在 cufile.log 中。常见原因之一可能是未启用内部线程池。有关如何启用它的信息,请参阅 cufile.json “execution”部分。

6. 高级故障排除#

本节提供有关排除一些高级问题的信息。

6.1. 解决无响应的挂起 cuFile* API#

要解决挂起的 cuFile API

  1. 检查 dmesg 中是否有任何内核崩溃/警告

    $ dmesg > warnings.txt. less warnings.txt
    
  2. 检查应用程序进程是否处于 D(不可中断)状态。

  3. 如果进程处于 D 状态

    1. 通过运行以下命令获取进程的 PID

      $ ps axf | grep ' D'
      
    2. 以 root 用户身份,获取 D 状态进程的回溯

      $ su root
      $ cat /proc/<pid>/stack
      
  4. 验证线程是否卡在内核中或用户空间中。有关更多信息,请查看 D 状态线程的回溯。

  5. 检查是否有任何线程显示 CPU 使用率过高。

    1. htopmpstat 工具应显示每个内核的 CPU 使用率。

    2. 获取 CPU 使用位置的调用图。以下代码段应缩小线程是挂起在用户空间还是内核中的范围

      $ perf top -g
      

6.2. 向客户支持发送相关数据#

本节介绍如何使用 NVSM 或 GDS 日志收集工具解决包含堆栈跟踪的内核崩溃问题。

DGX 操作系统

适用于启用预览网络仓库并安装了 NVSM 的 DGX BaseOS

$ sudo apt-get install nvsm
$ sudo nvsm dump health

有关运行 NVSM 命令的更多详细信息,请参阅 NVIDIA 系统管理用户指南

非 DGX

GDS 用户可以运行 GDS 日志收集工具 gds_log_collection.py,从系统中收集相关的调试信息,以便在出现 GDS IO 问题时使用。

以下突出显示了此工具捕获的一些重要信息

  • dmesg 输出和相关的内核日志文件。

  • 系统映射文件和 vmlinux 镜像

  • 相关模块的 modinfo 输出

  • /proc/cmdline 输出

  • IB 设备信息,如 ibdev2net 和 ibstatus

  • 操作系统发行版信息

  • Cpuinfo、meminfo

  • nvidia-fs 统计信息

  • 每个进程的信息,如 cufile.logcufile.jsongds_stats、堆栈指针

  • 任何用户指定的文件

要使用日志收集工具

$ sudo /usr/local/cuda/gds//tools/gdstools/gds_log_collection.py -h

此工具用于从系统中收集与调试相关的日志。

它收集日志,例如操作系统和内核信息、nvidia-fs 统计信息、dmesg 日志、系统日志、系统映射文件以及每个进程的日志,例如 cufile.jsoncufile.log、gdsstats、进程堆栈等等。

用法

./gds_log_collection.py [选项]

选项

-h 帮助

-f file1,file2,..(注意:‘,’ 之间不应有空格)

这些文件可以是除正在收集的文件之外的任何相关文件(例如崩溃文件)。

用法示例

sudo ./gds_log_colection.py - 收集所有相关日志。

sudo ./gds_log_colection.py -f file1,file2 - 收集所有相关文件以及用户指定的文件。

6.3. 解决 EIO 和堆栈跟踪警告导致的 IO 故障#

您可能会看到 EIO 导致的 IO 故障,以及包含 nvfs_mgroup_check_and_set 函数的堆栈跟踪警告。

这可能意味着 EXAScaler 文件系统没有遵守 O_DIRECT,而是回退到页缓存模式。GDS 在驱动程序中跟踪此信息并返回 EIO。

注意

警告 堆栈跟踪仅在内核模块的生命周期内观察到一次。您将收到 Error: Input/Output (EIO) 错误,但跟踪消息仅打印一次。如果您持续遇到此问题,请联系支持部门。

6.4. 控制 GPU BAR 内存使用量#

  1. 要显示每个 GPU 可用的 BAR 内存量,请运行以下命令

    $ /usr/local/cuda-x.y/gds/tools/gdscheck
    
  2. 查看输出,例如

GPU INFO:
 GPU Index: 0 bar:1 bar size (MB):32768
 GPU Index: 1 bar:1 bar size (MB):32768

GDS 在以下情况下使用 BAR 内存

  • 当进程调用 cuFileBufRegister 时。

  • 当 GDS 在内部使用缓存为每个 GPU 分配反弹缓冲区时。

注意

缓存和 BAR 内存使用量没有每个 GPU 的配置。

每个进程都可以通过 /etc/cufile.json 文件中的可配置属性来控制 BAR 内存的使用。

"properties": {

// device memory size for reserving bounce buffers for the entire GPU (in KB)
"max_device_cache_size" : 131072,
// limit on maximum memory that can be pinned for a given process (in KB)
"max_device_pinned_mem_size" : 33554432

}

.. note::

   This configuration is per process, and the configuration is set across all GPUs.

6.5. 确定要预留的缓存量#

默认情况下,在可配置的 max_device_cache_size 属性中设置了 128 MB 的缓存。但是,这并不意味着 GDS 预先为每个 GPU 分配了 128 MB 的内存。内存分配是根据需要动态完成的。分配完成后,不会清除缓存。

默认情况下,由于设置了 128 MB,缓存最多可以增长到 128 MB。设置缓存是特定于应用程序的,并且取决于工作负载。请参阅 GPUDirect Storage 最佳实践指南,以了解缓存的需求以及如何根据指南中的指导设置限制。

6.6. 监控 BAR 内存使用量#

没有办法监控每个进程的 BAR 内存使用量。但是,GDS 统计信息会跟踪所有进程的全局 BAR 使用量。有关更多信息,请参阅 GPU 为 B:D:F 0000:34:00.0/proc/driver/nvidia_fs/stats 中的以下统计信息输出

GPU 0000:34:00.0  uuid:12a86a5e-3002-108f-ee49-4b51266cdc07 : Registered_MB=32 Cache_MB=10

Registered_MB 跟踪应用程序显式使用 cuFileBufRegister API 时使用的 BAR 内存量。

Cache_MB 跟踪 GDS 用于内部缓存的 BAR 内存使用量。

6.7. 解决 ENOMEM 错误代码#

-12 ENOMEM 错误代码。

每个 GPU 都保留了一些 BAR 内存。cuFileBufRegister 函数使 GPU 虚拟内存范围下的页面可供第三方设备访问。此过程通过使用 nvidia_p2p_get_pages API 将 GPU 设备内存固定在 BAR 空间中来完成。如果应用程序尝试固定的内存超出可用的 BAR 空间,则 nvidia_p2p_get_pages API 将返回 -12 (ENOMEM) 错误代码。

为了避免 BAR 内存耗尽,开发人员应使用此输出来管理应用程序固定的内存量。管理员可以使用此输出来调查如何限制不同应用程序的固定内存。

6.8. GDS 和兼容模式#

要确定 GDS 兼容模式,请完成以下操作

  1. 在 /etc/cufile.json 文件中,验证 allow_compat_mode 是否设置为 true

  2. gdscheck -p 显示 allow_compat_mode 属性是否设置为 true

  3. 检查 cufile.log 文件中是否有 cufile IO mode: POSIX 消息。

    此消息位于热 IO 路径中,在其中记录每个实例会显著影响性能,因此仅当 /etc/cufile.json 文件中的 logging:level 显式设置为 TRACE 模式时,才会记录该消息。

6.9. 启用兼容模式#

应用程序开发人员可以使用兼容模式在以下条件下测试启用 cuFile 的库的应用程序

  • 当特定文件系统不支持 GDS 时。

  • 管理员未在系统中启用 nvidia-fs.ko 驱动程序。

要启用兼容模式

  1. 移除 nvidia-fs 内核驱动程序

    $ rmmod nvidia-fs
    
  2. 在 /etc/cufile.json 文件中,将 compat-mode 设置为 true

  3. CUFILE_FORCE_COMPAT_MODE 环境变量设置为 true。

现在,通过 cuFileRead/cuFileWrite 的 IO 将回退到 CPU 路径。

6.10. 跟踪启用兼容模式后的 IO#

当 GDS 在兼容模式下使用,并且在 /etc/cufile.json 文件中启用了 cufile_stats 时,您可以使用 gds_stats 或其他标准 Linux 工具(例如 strace、iostat、iotop、SAR、ftrace 和 perf)。您还可以使用 BPF 编译器集合工具来跟踪和监控 IO。

启用兼容模式后,在内部,cuFileReadcuFileWrite 分别使用 POSIX pread 和 pwrite 系统调用。

6.11. 绕过 GPUDirect Storage#

在某些情况下,您可以绕过 GDS。

有一些可调参数,GDS IO 和 POSIX IO 可以同时通过。以下是在无需移除 GDS 驱动程序的情况下可以绕过 GDS 的情况

  • 在受支持的文件系统和块设备上。

    /etc/cufile.json 文件中,如果 posix_unaligned_writes 配置属性设置为 true,则未对齐的写入将回退到兼容模式,并且不会通过 GDS。有关受支持文件系统的列表,请参阅 安装 GDS 前的准备工作

  • 在 EXAScaler 文件系统上

    在 /etc/cufile.json 文件中,如果 posix_gds_min_kb config 属性设置为某个值(以 KB 为单位),则大小小于或等于设置值的 IO 将回退到 POSIX 模式。例如,如果 posix_gds_min_kb 设置为 8KB,则大小小于或等于 8KB 的 IO 将回退到 POSIX 模式。

  • 在 WekaIO 文件系统上

注意

目前,cuFileWrite 将始终回退到 POSIX 模式。

/etc/cufile.json 文件中,如果 allow-compat-mode config 属性设置为 true

  • 如果无法建立 RDMA 连接和/或内存注册,cuFileRead 将回退到 POSIX 模式。

  • cuFileRead 无法为非 4K 对齐的 GPU VA 地址分配内部反弹缓冲区。

有关更多信息,请参阅 GPUDirect Storage 最佳实践指南

6.12. GDS 不适用于挂载#

在以下情况下,GDS 将不用于挂载

  • 当系统上未加载必要的 GDS 驱动程序时。

  • 与该挂载点关联的文件系统不受 GDS 支持。

  • 挂载点在 /etc/cufile.json 文件中被列入拒绝列表。

6.13. 在同一文件上同时运行 GPUDirect Storage IO 和 POSIX IO#

由于文件在 O_DIRECT 模式下为 GDS 打开,因此应用程序应避免将 O_DIRECT 和普通 I/O 混合用于同一文件以及同一文件中的重叠字节区域。

即使文件系统在这种情况下正确处理了数据一致性问题,总体 I/O 吞吐量也可能比单独使用任一模式要慢。同样,应用程序应避免将文件的 mmap(2) 与同一文件的直接 I/O 混合使用。有关其他 O_DIRECT 限制的信息,请参阅特定于文件系统的文档。

6.14. 使用 GPUDirect Storage 运行数据验证测试#

GDS 有一个内部数据验证实用程序 gdsio_verify,用于测试读取和写入的数据完整性。运行 gdsio_verify -h 获取详细的用法信息。

例如

$ /usr/local/cuda-11.2/gds/tools/gds_verify -f /mnt/ai200/fio-seq-writes-1 -d 0 -o 0 -s 1G -n 1 -m 1

示例输出

gpu index :0,file :/mnt/ai200/fio-seq-writes-1, RING buffer size :0,
gpu buffer alignment :0, gpu buffer offset :0, file offset :0,
io_requested :1073741824, bufregister :true, sync :1, nr ios :1,
fsync :0,
address = 0x560d32c17000
Data Verification Success

注意

此测试完成通过 GDS 的读取和写入的数据验证。

7. 性能故障排除#

本节介绍与性能相关的问题。

7.1. 使用 GDS 运行性能基准测试#

您可以使用 GDS 运行性能基准测试,并将结果与 CPU 数字进行比较。

GDS 有一个自研的基准测试实用程序 /usr/local/cuda-x.y/gds/tools/gdsio,可帮助您将 GDS IO 吞吐量数字与 CPU IO 吞吐量进行比较。运行 gdsio -h 获取详细的用法信息。

以下是一些示例

GDS:存储 –> GPU 内存

$ /usr/local/cuda-x.y/tools/gdsio -f /mnt/ai200/fio-seq-writes-1 -d 0 -w 4 -s 10G -i 1M -I 0 -x 0

存储 –> CPU 内存

$ /usr/local/cuda-x.y/tools/gdsio -f /mnt/ai200/fio-seq-writes-1 -d 0 -w 4 -s 10G -i 1M -I 0 -x 1

存储 –> CPU 内存 –> GPU 内存

$ /usr/local/cuda-x.y/tool/gdsio -f /mnt/ai200/fio-seq-writes-1 -d 0 -w 4 -s 10G -i 1M -I 0 -x 2

使用批处理模式的存储 –> GPU 内存

$ /usr/local/cuda-x.y/tool/gdsio -f /mnt/ai200/fio-seq-read-1 -d 0 -w 4 -s 10G -i 1M -I 0 -x 6

使用异步流模式的存储 –> GPU 内存

$ /usr/local/cuda-x.y/tool/gdsio -f /mnt/ai200/fio-seq-read-1 -d 0 -w 4 -s 10G -i 1M -I 0 -x 5

7.2. 跟踪 GPUDirect Storage 是否正在使用内部缓存#

您可以确定 GDS 是否正在使用内部缓存。

先决条件:在开始之前,请阅读 GPUDirect Storage 最佳实践指南

GDS 统计信息具有每个 GPU 的统计信息,并显示 GPU 总线设备功能 (BDF) 信息的每一部分。如果 GPU 上的 cache_MB 字段处于活动状态,则 GDS 正在内部使用缓存来完成 IO。

当以下条件之一为真时,GDS 可能会使用内部缓存

  • cuFileRead/cuFileWrite 中发出的 file_offset 未 4K 对齐。

  • cuFileRead/cuFileWrite 调用中的大小未 4K 对齐。

  • cuFileRead/cuFileWrite 中发出的 devPtr_base 未 4K 对齐。

  • cuFileRead/cuFileWrite 中发出的 devPtr_base+devPtr_offset 未 4K 对齐。

7.3. 跟踪 IO 何时跨越 PCIe 根联合体并影响性能#

您可以跟踪 IO 何时跨越 PCIe 根联合体并影响性能。

有关更多信息,请参阅 检查内核文件系统和存储驱动程序的对等亲缘性统计信息

7.4. 使用 GPUDirect 统计信息监控 CPU 活动#

虽然您不能使用 GDS 统计信息来监控 CPU 活动,但您可以使用以下 Linux 工具来完成此任务

  • htop

  • perf

  • mpstat

7.5. 使用 cuFile-* API 监控性能和跟踪#

您可以使用 cuFile-* API 监控性能和跟踪。

您可以使用 FTrace、Perf 或 BCC-BPF 工具来监控性能和跟踪。确保您拥有可用于使用标准 Linux IO 工具跟踪和监控性能的符号。

7.6. 示例:使用 Linux 跟踪工具#

cuFileBufRegister 函数使 GPU 虚拟内存范围下的页面可供第三方设备访问。此过程通过将 GPU 设备内存固定在 BAR 空间中来完成,这是一个开销很大的操作,可能需要几毫秒。

您可以使用 BCC/BPF 工具来跟踪 cuFileBufRegister API,了解 Linux 内核中正在发生的事情,并了解为什么此过程开销很大。

场景

  1. 您正在运行一个包含 8 个线程的工作负载,其中每个线程都在发出 cuFileBufRegister 以固定到 GPU 内存。

    $ ./gdsio -f /mnt/ai200/seq-writes-1 -d 0 -w 8 -s 10G -i 1M -I 0 -x 0
    
  2. 当 IO 正在进行时,使用跟踪工具来了解 cuFileBufRegister 正在发生什么

    $ /usr/share/bcc/tools# ./funccount -Ti 1 nvfs_mgroup_pin_shadow_pages
    
  3. 查看示例输出

    15:04:56
    FUNC                                    COUNT
    nvfs_mgroup_pin_shadow_pages            8
    

    如您所见,nvfs_mgroup_pin_shadow_pages 函数已被调用 8 次,每个线程一次。

  4. 要查看该函数的延迟,请运行

    $ /usr/share/bcc/tools# ./funclatency -i 1 nvfs_mgroup_pin_shadow_pages
    
  5. 查看输出

    Tracing 1 functions for "nvfs_mgroup_pin_shadow_pages"... Hit Ctrl-C to end.
    
         nsecs               : count     distribution
             0 -> 1          : 0        |                                        |
             2 -> 3          : 0        |                                        |
             4 -> 7          : 0        |                                        |
             8 -> 15         : 0        |                                        |
            16 -> 31         : 0        |                                        |
            32 -> 63         : 0        |                                        |
            64 -> 127        : 0        |                                        |
           128 -> 255        : 0        |                                        |
           256 -> 511        : 0        |                                        |
           512 -> 1023       : 0        |                                        |
          1024 -> 2047       : 0        |                                        |
          2048 -> 4095       : 0        |                                        |
          4096 -> 8191       : 0        |                                        |
          8192 -> 16383      : 1        |*****                                   |
         16384 -> 32767      : 7        |****************************************|
    

    七次调用 nvfs_mgroup_pin_shadow_pages 函数大约花费了 16-32 微秒。这可能来自用于固定影子页面的 Linux 内核 get_user_pages_fast

    cuFileBufRegister 调用 nvidia_p2p_get_pages NVIDIA 驱动程序函数,以将 GPU 设备内存固定在 BAR 空间中。此信息通过运行 $ perf top -g 并获取 cuFileBufRegister 的调用图来获得。

以下示例说明了 nvidia_p2p_get_pages 的开销

$ /usr/share/bcc/tools# ./funclatency -Ti 1 nvidia_p2p_get_pages

15:45:19
nsecs               : count     distribution
  0 -> 1          : 0        |                                        |
  2 -> 3          : 0        |                                        |
  4 -> 7          : 0        |                                        |
  8 -> 15         : 0        |                                        |
 16 -> 31         : 0        |                                        |
 32 -> 63         : 0        |                                        |
 64 -> 127        : 0        |                                        |
128 -> 255        : 0        |                                        |
256 -> 511        : 0        |                                        |
512 -> 1023       : 0        |                                        |
1024 -> 2047       : 0        |                                        |
2048 -> 4095       : 0        |                                        |
4096 -> 8191       : 0        |                                        |
8192 -> 16383      : 0        |                                        |
16384 -> 32767      : 0        |                                        |
32768 -> 65535      : 0        |                                        |
65536 -> 131071     : 0        |                                        |
131072 -> 262143     : 0        |                                        |
262144 -> 524287     : 2        |*************                           |
524288 -> 1048575    : 6        |****************************************|

7.7. 跟踪 cuFile* API#

您可以使用 nvprof/NVIDIA Nsight 来跟踪 cuFile* API。

NVTX 静态跟踪点可用于 libcufile.so 库中的公共接口。启用这些静态跟踪点后,您可以像查看任何其他 CUDA 符号一样在 NVIDIA Nsight 中查看这些跟踪。

您可以使用 /etc/cufile.json 中的 JSON 配置启用 NVTX 跟踪

"profile": {
             // nvtx profiling on(true)/off(false)
             "nvtx": true,
           },

7.8. 使用动态路由提高性能#

在 GPU 和存储 NIC 之间的 IO 传输涉及跨 PCIe 主机桥的 PCIe 流量的平台上,GPUDirect Storage IO 可能看不到很高的吞吐量,尤其是在写入时。此外,某些芯片组可能仅支持主机桥流量的 P2P 读取流量。在这种情况下,可以启用动态路由功能来调试和识别哪种路由策略被认为最适合此类平台。这可以通过使用 gdsio 工具的单 GPU 写入测试来说明,其中有一个存储 NIC 和 10 个 GPU,并且 GPU 之间启用了 NVLINK 访问。启用动态路由后,即使 GPU 和 NIC 可能位于不同的插槽上,GDS 仍然可以实现最大可能的写入吞吐量。

$ cat /etc/cufile.json | grep rdma_dev
         "rdma_dev_addr_list": [ "192.168.0.19" ],

动态路由关闭

$ cat /etc/cufile.json | grep routing
         "rdma_dynamic_routing": false
$ for i in 0 1 2 3 4 5 6 7 8 9 10;
    do
 ./gdsio -f /mnt/nfs/file1 -d $i -n 0 -w 4 -s 1G -i 1M -x 0 -I 1 -p -T 15 ;
    done
IoType: WRITE XferType: GPUD Threads: 4 DataSetSize: 45792256/4194304(KiB) IOSize: 1024(KiB) Throughput: 2.873560 GiB/sec, Avg_Latency: 1359.280174 usecs ops: 44719 total_time 15.197491 secs
    url index :0, urlname :192.168.0.2 urlport :18515
IoType: WRITE XferType: GPUD Threads: 4 DataSetSize: 45603840/4194304(KiB) IOSize: 1024(KiB) Throughput: 2.867613 GiB/sec, Avg_Latency: 1363.891220 usecs ops: 44535 total_time 15.166344 secs
    url index :0, urlname :192.168.0.2 urlport :18515
IoType: WRITE XferType: GPUD Threads: 4 DataSetSize: 42013696/4194304(KiB) IOSize: 1024(KiB) Throughput: 2.848411 GiB/sec, Avg_Latency: 1373.154082 usecs ops: 41029 total_time 14.066573 secs
    url index :0, urlname :192.168.0.2 urlport :18515
IoType: WRITE XferType: GPUD Threads: 4 DataSetSize: 43517952/4194304(KiB) IOSize: 1024(KiB) Throughput: 2.880763 GiB/sec, Avg_Latency: 1358.207427 usecs ops: 42498 total_time 14.406582 secs
    url index :0, urlname :192.168.0.2 urlport :18515
IoType: WRITE XferType: GPUD Threads: 4 DataSetSize: 34889728/4194304(KiB) IOSize: 1024(KiB) Throughput: 2.341907 GiB/sec, Avg_Latency: 1669.108902 usecs ops: 34072 total_time 14.207836 secs
    url index :0, urlname :192.168.0.2 urlport :18515
IoType: WRITE XferType: GPUD Threads: 4 DataSetSize: 36955136/4194304(KiB) IOSize: 1024(KiB) Throughput: 2.325239 GiB/sec, Avg_Latency: 1680.001220 usecs ops: 36089 total_time 15.156790 secs
    url index :0, urlname :192.168.0.2 urlport :18515
IoType: WRITE XferType: GPUD Threads: 4 DataSetSize: 37075968/4194304(KiB) IOSize: 1024(KiB) Throughput: 2.351491 GiB/sec, Avg_Latency: 1661.198487 usecs ops: 36207 total_time 15.036584 secs
    url index :0, urlname :192.168.0.2 urlport :18515
IoType: WRITE XferType: GPUD Threads: 4 DataSetSize: 35066880/4194304(KiB) IOSize: 1024(KiB) Throughput: 2.235654 GiB/sec, Avg_Latency: 1748.638950 usecs ops: 34245 total_time 14.958656 secs
    url index :0, urlname :192.168.0.2 urlport :18515
IoType: WRITE XferType: GPUD Threads: 4 DataSetSize: 134095872/4194304(KiB) IOSize: 1024(KiB) Throughput: 8.940253 GiB/sec, Avg_Latency: 436.982682 usecs ops: 130953 total_time 14.304269 secs
    url index :0, urlname :192.168.0.2 urlport :18515
IoType: WRITE XferType: GPUD Threads: 4 DataSetSize: 135974912/4194304(KiB) IOSize: 1024(KiB) Throughput: 8.932070 GiB/sec, Avg_Latency: 437.334849 usecs ops: 132788 total_time 14.517998 secs
    url index :0, urlname :192.168.0.2 urlport :18515
IoType: WRITE XferType: GPUD Threads: 4 DataSetSize: 174486528/4194304(KiB) IOSize: 1024(KiB) Throughput: 11.238476 GiB/sec, Avg_Latency: 347.603610 usecs ops: 170397 total_time 14.806573 secs

动态路由开启(启用 nvlinks)

$ cat /etc/cufile.json | grep routing
         "rdma_dynamic_routing": true
         "rdma_dynamic_routing_order": [ "GPU_MEM_NVLINKS"]

$ for i in 0 1 2 3 4 5 6 7 8 9 10;
do
./gdsio -f  /mnt/nfs/file1 -d $i -n 0 -w 4 -s 1G -i 1M -x 0 -I 1 -p -T 15 ;
done
IoType: WRITE XferType: GPUD Threads: 4 DataSetSize: 134479872/4194304(KiB) IOSize: 1024(KiB) Throughput: 8.885214 GiB/sec, Avg_Latency: 437.942083 usecs ops: 131328 total_time 14.434092 secs
    url index :0, urlname :192.168.0.2 urlport :18515
IoType: WRITE XferType: GPUD Threads: 4 DataSetSize: 138331136/4194304(KiB) IOSize: 1024(KiB) Throughput: 8.891407 GiB/sec, Avg_Latency: 437.668104 usecs ops: 135089 total_time 14.837118 secs
    url index :0, urlname :192.168.0.2 urlport :18515
IoType: WRITE XferType: GPUD Threads: 4 DataSetSize: 133800960/4194304(KiB) IOSize: 1024(KiB) Throughput: 8.897250 GiB/sec, Avg_Latency: 437.305565 usecs ops: 130665 total_time 14.341795 secs
    url index :0, urlname :192.168.0.2 urlport :18515
IoType: WRITE XferType: GPUD Threads: 4 DataSetSize: 133990400/4194304(KiB) IOSize: 1024(KiB) Throughput: 8.888714 GiB/sec, Avg_Latency: 437.751327 usecs ops: 130850 total_time 14.375893 secs
    url index :0, urlname :192.168.0.2 urlport :18515
IoType: WRITE XferType: GPUD Threads: 4 DataSetSize: 141934592/4194304(KiB) IOSize: 1024(KiB) Throughput: 8.905190 GiB/sec, Avg_Latency: 437.032919 usecs ops: 138608 total_time 15.200055 secs
    url index :0, urlname :192.168.0.2 urlport :18515
IoType: WRITE XferType: GPUD Threads: 4 DataSetSize: 133379072/4194304(KiB) IOSize: 1024(KiB) Throughput: 8.892493 GiB/sec, Avg_Latency: 437.488259 usecs ops: 130253 total_time 14.304222 secs
    url index :0, urlname :192.168.0.2 urlport :18515
IoType: WRITE XferType: GPUD Threads: 4 DataSetSize: 142271488/4194304(KiB) IOSize: 1024(KiB) Throughput: 8.892426 GiB/sec, Avg_Latency: 437.660016 usecs ops: 138937 total_time 15.258004 secs
    url index :0, urlname :192.168.0.2 urlport :18515
IoType: WRITE XferType: GPUD Threads: 4 DataSetSize: 134951936/4194304(KiB) IOSize: 1024(KiB) Throughput: 8.890496 GiB/sec, Avg_Latency: 437.661177 usecs ops: 131789 total_time 14.476154 secs
    url index :0, urlname :192.168.0.2 urlport :18515
IoType: WRITE XferType: GPUD Threads: 4 DataSetSize: 132667392/4194304(KiB) IOSize: 1024(KiB) Throughput: 8.930203 GiB/sec, Avg_Latency: 437.420830 usecs ops: 129558 total_time 14.167817 secs
    url index :0, urlname :192.168.0.2 urlport :18515
IoType: WRITE XferType: GPUD Threads: 4 DataSetSize: 137982976/4194304(KiB) IOSize: 1024(KiB) Throughput: 8.936189 GiB/sec, Avg_Latency: 437.123356 usecs ops: 134749 total_time 14.725608 secs
    url index :0, urlname :192.168.0.2 urlport :18515
IoType: WRITE XferType: GPUD Threads: 4 DataSetSize: 170469376/4194304(KiB) IOSize: 1024(KiB) Throughput: 11.231479 GiB/sec, Avg_Latency: 347.818052 usecs ops: 166474 total_time 14.474698 secs

8. IO 活动故障排除#

本节介绍与 IO 活动以及与 Linux 其余部分的交互相关的问题。

8.1. 管理页缓存和磁盘中数据的一致性#

使用 GDS 时,文件通常以 O_DIRECT 模式打开。当 IO 完成时,在 DIRECT IO 的上下文中,它会绕过页缓存。

从 CUDA 工具包 12.2(GDS 版本 1.7.x)开始,文件也可以以非 O_DIRECT 模式打开。即使在这种情况下,只要库软件认为合适,它也会遵循启用 GDS 的 O_DIRECT 路径。这默认情况下可以保持数据一致性。

  • 在 EXAScaler 文件系统上

    • 对于读取,IO 会绕过页缓存并直接从后端存储获取数据。

    • 当发出写入时,nvidia-fs 驱动程序将尝试刷新页缓存中偏移量-长度范围内的数据,然后再向 VFS 子系统发出写入。

    • 跟踪此信息的统计信息是

      • pg_cache

      • pg_cache_fail

      • pg_cache_eio

  • 在 WekaIO 文件系统上

    • 对于读取,IO 会绕过页缓存并直接从后端存储获取数据。

9. EXAScaler 文件系统 LNet 故障排除#

本节介绍如何排查 EXAScaler 文件系统的问题。

9.1. 确定 EXAScaler 文件系统客户端模块版本#

要检查 EXAScaler 文件系统客户端版本,请在安装 EXAScaler 文件系统后检查 dmesg。

注意

EXAScaler 服务器版本应为 EXA-5.2。

下表提供了已使用 DDN AI200 和 DDN AI400 系统测试过的客户端内核模块版本列表

表 2 测试的内核模块版本#

DDN 客户端版本

内核版本

MLNX_OFED 版本

2.12.3_ddn28

4.15.0

MLNX_OFED 4.7

2.12.3_ddn29

4.15.0

MLNX_OFED 4.7

2.12.3_ddn39

4.15.0

MLNX_OFED 5.1

2.12.5_ddn4

5.4.0

MLNX_OFED 5.1

2.12.6_ddn19

5.4.0

MLNX_OFED 5.3

要验证客户端版本,请运行以下命令

$ sudo lctl get_param version

示例输出

Lustre version: 2.12.3_ddn39

9.2. 检查客户端上的 LNet 网络设置#

要检查客户端上的 LNet 网络设置

  1. 运行以下命令。

    $ sudo lnetctl net show:
    
  2. 查看输出,例如

    net:
       - net type: lo
    

9.3. 检查对等节点的健康状况#

Lnet 健康值 1000 是网络接口可以报告的最佳值。任何小于 1000 的值都表示接口以降级模式运行,并且遇到了一些错误。

  1. 运行以下命令;

    $ sudo lnetctl net show -v 3 | grep health
    
  2. 查看输出,例如

    health stats:
          health stats:
              health value: 1000
          health stats:
              health value: 1000
          health stats:
              health value: 1000
          health stats:
              health value: 1000
          health stats:
              health value: 1000
          health stats:
              health value: 1000
          health stats:
              health value: 1000
          health stats:
              health value: 1000
    

9.4. 检查多路导轨支持#

要验证是否支持多路导轨

  1. 运行以下命令

    $ sudo lnetctl peer show | grep -i Multi-Rail:
    
  2. 查看输出,例如

    Multi-Rail: True
    

9.5. 检查 GDS 对等亲缘性#

对于对等亲缘性,您需要检查预期的接口是否正被用于关联的 GPU。

下面的代码片段描述了一个在特定 GPU 上运行负载的测试。该测试验证执行发送和接收的接口是否是最近的接口,并且是否正确映射到 GPU。有关用于检查对等亲缘性的指标的更多信息,请参阅重置 nvidia-fs 统计信息检查对等亲缘性统计信息以了解内核文件系统和存储驱动程序

您可以为工具部分运行 gdsio 测试并监控 LNET 统计信息。有关更多信息,请参阅自述文件。在 gdsio 测试中,已在 GPU 0 上完成写入测试。NVIDIA DGX-2 平台上 GPU 0 的预期 NIC 接口是 ib0。lnetctl net 显示统计信息之前已捕获,并且在 gdsio 测试之后,您可以看到 RPC 发送和接收发生在 IB0 上。

  1. 运行 gdsio 测试。

  2. 查看输出,例如

    $ sudo lustre_rmmod
    $ sudo mount -t lustre 192.168.1.61@o2ib,192.168.1.62@o2ib:/ai200 /mnt/ai200/
    $ sudo lnetctl net show -v 3 | grep health
              health stats:
                  health value: 0
              health stats:
                  health value: 1000
              health stats:
                  health value: 1000
              health stats:
                  health value: 1000
              health stats:
                  health value: 1000
              health stats:
                  health value: 1000
              health stats:
                  health value: 1000
              health stats:
                  health value: 1000
    
    $ sudo lnetctl net show -v 3 | grep -B 2 -i 'send_count\|recv_count'
              status: up
              statistics:
                  send_count: 0
                  recv_count: 0
    --
                  0: ib0
              statistics:
                  send_count: 3
                  recv_count: 3
    --
                  0: ib2
              statistics:
                  send_count: 3
                  recv_count: 3
    --
                  0: ib3
              statistics:
                  send_count: 2
                  recv_count: 2
    --
                  0: ib4
              statistics:
                  send_count: 13
                  recv_count: 13
    --
                  0: ib5
              statistics:
                  send_count: 12
                  recv_count: 12
    --
                  0: ib6
              statistics:
                  send_count: 12
                  recv_count: 12
    --
                  0: ib7
              statistics:
                  send_count: 11
                  recv_count: 11
    
    $ echo 1 > /sys/module/nvidia_fs/parameters/peer_stats_enabled
    
    $ /usr/local/cuda-x.y/tools/gdsio -f /mnt/ai200/test -d 0 -n 0 -w 1 -s 1G -i 4K -x 0 -I 1
    IoType: WRITE XferType: GPUD Threads: 1  DataSetSize: 1073741824/1073741824 IOSize: 4(KB),Throughput: 0.004727 GB/sec, Avg_Latency: 807.026154 usecs ops: 262144 total_time 211562847.000000 usecs
    
    $ sudo lnetctl net show -v 3 | grep -B 2 -i 'send_count\|recv_count'
    
              status: up
              statistics:
                  send_count: 0
                  recv_count: 0
    --
                  0: ib0
              statistics:
                  send_count: 262149
                  recv_count: 524293
    --
                  0: ib2
              statistics:
                  send_count: 6
                  recv_count: 6
    --
                  0: ib3
              statistics:
                  send_count: 6
                  recv_count: 6
    --
                  0: ib4
              statistics:
                  send_count: 33
                  recv_count: 33
    --
                  0: ib5
              statistics:
                  send_count: 32
                  recv_count: 32
    --
                  0: ib6
              statistics:
                  send_count: 32
                  recv_count: 32
    --
                  0: ib7
              statistics:
                  send_count: 32
                  recv_count: 32
    
    $ cat /proc/driver/nvidia-fs/peer_affinity
    GPU P2P DMA distribution based on pci-distance
    
    (last column indicates p2p via root complex)
    GPU :0000:be:00.0 :0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
    GPU :0000:3b:00.0 :0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
    GPU :0000:e7:00.0 :0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
    GPU :0000:e5:00.0 :0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
    GPU :0000:e0:00.0 :0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
    GPU :0000:57:00.0 :0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
    GPU :0000:39:00.0 :0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
    GPU :0000:36:00.0 :0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
    GPU :0000:e2:00.0 :0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
    GPU :0000:59:00.0 :0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
    GPU :0000:b7:00.0 :0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
    GPU :0000:b9:00.0 :0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
    GPU :0000:bc:00.0 :0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
    GPU :0000:34:00.0 :0 0 23872512 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
    GPU :0000:5e:00.0 :0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
    GPU :0000:5c:00.0 :0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
    

9.6. 检查 LNet 级别错误#

这些错误会影响各个 NIC 的健康状况,并影响 EXAScaler 文件系统如何选择最佳对等节点,从而影响 GDS 性能。

注意

要运行这些命令,您必须具有 sudo 权限。

  1. 运行以下命令

    $ cat /proc/driver/nvidia-fs/peer_affinity
    
  2. 查看输出,例如

    GPU P2P DMA distribution based on pci-distance
    (last column indicates p2p via root complex)
    GPU :0000:be:00.0 :0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 GPU :0000:3b:00.0 :0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 GPU :0000:e7:00.0 :0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 GPU :0000:e5:00.0 :0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 GPU :0000:e0:00.0 :0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 GPU :0000:57:00.0 :0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1276417
    
    (Note : if peer traffic goes over Root-Port, one of the reasons might be that health of nearest NIC might be  affected)
    GPU :0000:39:00.0 :0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
    GPU :0000:36:00.0 :0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
    GPU :0000:e2:00.0 :0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
    GPU :0000:59:00.0 :0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
    GPU :0000:b7:00.0 :0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
    GPU :0000:b9:00.0 :0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
    GPU :0000:bc:00.0 :0 0 7056141 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
    GPU :0000:34:00.0 :0 0 8356175 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
    GPU :0000:5e:00.0 :0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
    GPU :0000:5c:00.0 :0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
    
    $ sudo lnetctl stats show
    statistics:
        msgs_alloc: 1
        msgs_max: 126
        rst_alloc: 25
        errors: 0
        send_count: 243901
        resend_count: 1
        response_timeout_count: 1935
        local_interrupt_count: 0
        local_dropped_count: 208
        local_aborted_count: 0
        local_no_route_count: 0
        local_timeout_count: 1730
        local_error_count: 0
        remote_dropped_count: 0
        remote_error_count: 0
        remote_timeout_count: 0
        network_timeout_count: 0
        recv_count: 564436
        route_count: 0
        drop_count: 0
        send_length: 336176013248
        recv_length: 95073248
        route_length: 0
        drop_length: 0
     lnetctl net show -v 4
    
    net:
        - net type: o2ib
          local NI(s):
            - nid: 192.168.1.71@o2ib
              status: up
              interfaces:
                  0: ib0
              statistics:
                  send_count: 171621
                  recv_count: 459717
                  drop_count: 0
              sent_stats:
                  put: 119492
                  get: 52129
                  reply: 0
                  ack: 0
                  hello: 0
              received_stats:
                  put: 119492
                  get: 0
                  reply: 340225
                  ack: 0
                  hello: 0
              dropped_stats:
                  put: 0
                  get: 0
                  reply: 0
                  ack: 0
                  hello: 0
              health stats:
                  health value: 1000
                  interrupts: 0
                  dropped: 0
                  aborted: 0
                  no route: 0
                  timeouts: 0
                  error: 0
              tunables:
                  peer_timeout: 180
                  peer_credits: 32
                  peer_buffer_credits: 0
                  credits: 256
                  peercredits_hiw: 16
                  map_on_demand: 1
                  concurrent_sends: 64
                  fmr_pool_size: 512
                  fmr_flush_trigger: 384
                  fmr_cache: 1
                  ntx: 512
                  conns_per_peer: 1
              lnd tunables:
              dev cpt: 0
              tcp bonding: 0
              CPT: "[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23]"
            - nid: 192.168.2.71@o2ib
              status: up
              interfaces:
                  0: ib1
              statistics:
                  send_count: 79
                  recv_count: 79
                  drop_count: 0
              sent_stats:
                  put: 78
                  get: 1
                  reply: 0
                  ack: 0
                  hello: 0
              received_stats:
                  put: 78
                  get: 0
                  reply: 1
                  ack: 0
                  hello: 0
              dropped_stats:
                  put: 0
                  get: 0
                  reply: 0
                  ack: 0
                  hello: 0
              health stats:
                  health value: 979
                  interrupts: 0
                  dropped: 0
                  aborted: 0
                  no route: 0
                  timeouts: 1
                  error: 0
              tunables:
                  peer_timeout: 180
                  peer_credits: 32
                  peer_buffer_credits: 0
                  credits: 256
                  peercredits_hiw: 16
                  map_on_demand: 1
                  concurrent_sends: 64
                  fmr_pool_size: 512
                  fmr_flush_trigger: 384
                  fmr_cache: 1
                  ntx: 512
                  conns_per_peer: 1
              lnd tunables:
              dev cpt: 0
              tcp bonding: 0
              CPT: "[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23]"
            - nid: 192.168.2.72@o2ib
              status: up
              interfaces:
                  0: ib3
              statistics:
                  send_count: 52154
                  recv_count: 52154
                  drop_count: 0
              sent_stats:
                  put: 25
                  get: 52129
                  reply: 0
                  ack: 0
                  hello: 0
              received_stats:
                  put: 25
                  get: 52129
                  reply: 0
                  ack: 0
                  hello: 0
              dropped_stats:
                  put: 0
                  get: 0
                  reply: 0
                  ack: 0
                  hello: 0
              health stats:
                  health value: 66
                  interrupts: 0
                  dropped: 208
                  aborted: 0
                  no route: 0
                  timeouts: 1735
                  error: 0
              tunables:
                  peer_timeout: 180
                  peer_credits: 32
                  peer_buffer_credits: 0
                  credits: 256
                  peercredits_hiw: 16
                  map_on_demand: 1
                  concurrent_sends: 64
                  fmr_pool_size: 512
                  fmr_flush_trigger: 384
                  fmr_cache: 1
                  ntx: 512
                  conns_per_peer: 1
              lnd tunables:
              dev cpt: 0
              tcp bonding: 0
             CPT: "[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23]"
    

如果您看到递增的错误统计信息,请捕获网络日志记录并提供此信息以进行调试

$ lctl set_param debug=+net
# reproduce the problem
$ lctl dk > logfile.dk

9.7. 解决 LNet NID 因超时导致的健康状况下降问题#

对于 DGX 等具有多个接口的大型机器,如果 Linux 路由设置不正确,可能会出现连接故障和其他意外行为。

用于解决本地连接超时的典型网络设置是

sysctl -w net.ipv4.conf.all.accept_local=1

还有用于解决 LNet 网络问题的通用指针。有关更多信息,请参阅 MR 集群设置

9.8. 配置具有多个 OST 的 LNet 网络以实现最佳对等节点选择#

当有多个 OST(对象存储目标),并且每个 OST 都是双接口时,您需要在客户端配置的每个 LNet 上都拥有一个接口。

例如,客户端侧有以下两个 LNet 子网

  • o2ib

  • o2ib1

服务器只有一个 Lnet 子网,o2ib。在这种情况下,路由不是最佳的,因为您将 IB 选择逻辑限制为一组设备,这些设备可能不是离 GPU 最近的设备。除了连接到 OST2 的 LNet 之外,没有其他方法可以访问 OST2。

流向此 OST 的流量永远不是最佳的,并且此配置可能会影响整体吞吐量和延迟。但是,如果您将服务器配置为使用两个网络 o2ib0o2ib1,则可以通过这两个网络访问 OST1 和 OST2。当选择算法运行时,它将确定最佳路径是例如通过 o2ib1 的 OST2。

  1. 要配置客户端 LNET,请运行以下命令

    $ sudo lnetctl net show
    
  2. 查看输出,例如

    net:
        - net type: lo
          local NI(s):
            - nid: 0@lo
              status: up
        - net type: o2ib
          local NI(s):
            - nid: 192.168.1.71@o2ib
              status: up
              interfaces:
                  0: ib0
            - nid: 192.168.1.72@o2ib
              status: up
              interfaces:
                  0: ib2
            - nid: 192.168.1.73@o2ib
              status: up
              interfaces:
                  0: ib4
            - nid: 192.168.1.74@o2ib
              status: up
              interfaces:
                  0: ib6
        - net type: o2ib1
          local NI(s):
            - nid: 192.168.2.71@o2ib1
              status: up
              interfaces:
                  0: ib1
            - nid: 192.168.2.72@o2ib1
              status: up
              interfaces:
                  0: ib3
            - nid: 192.168.2.73@o2ib1
              status: up
              interfaces:
                  0: ib5
            - nid: 192.168.2.74@o2ib1
              status: up
              interfaces:
                  0: ib7
    

对于最佳配置,LNet 对等节点应显示两个 LNet 子网。

在这种情况下,主要 nid 只有一个 o2ib

$ sudo lnetctl peer show

示例输出

peer:
    - primary nid: 192.168.1.62@o2ib
      Multi-Rail: True
      peer ni:
        - nid: 192.168.1.62@o2ib
          state: NA
        - nid: 192.168.2.62@o2ib1
          state: NA
       - primary nid: 192.168.1.61@o2ib
      Multi-Rail: True
      peer ni:
        - nid: 192.168.1.61@o2ib
          state: NA
        - nid: 192.168.2.61@o2ib1
          state: NA

从服务器端,这是一个次优 LNet 配置的示例

[root@ai200-090a-vm01 ~]# lnetctl net show
net:
    - net type: lo
      local NI(s):
        - nid: 0@lo
          status: up
    - net type: o2ib (o2ib1 is not present)
      local NI(s):
        - nid: 192.168.1.62@o2ib
          status: up
          interfaces:
              0: ib0
        - nid: 192.168.2.62@o2ib
          status: up
          interfaces:
              0: ib1

这是一个非最佳情况的 IB 配置示例,其中文件被条带化到两个 OST 上,并且存在顺序读取

$ ibdev2netdev -v

0000:b8:00.1 mlx5_13 (MT4123 - MCX653106A-ECAT) ConnectX-6 VPI adapter card, 100Gb/s (HDR100, EDR IB and 100GbE), dual-port QSFP56                                                                                                    fw 20.26.4012 port 1 (ACTIVE) ==> ib4 (Up) (o2ib)

ib4: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 2044

        inet 192.168.1.73  netmask 255.255.255.0  broadcast 192.168.1.255

0000:bd:00.1 mlx5_15 (MT4123 - MCX653106A-ECAT) ConnectX-6 VPI adapter card, 100Gb/s (HDR100, EDR IB and 100GbE), dual-port QSFP56                                                                                                     fw 20.26.4012 port 1 (ACTIVE) ==> ib5 (Up) (o2ib1)

 ib5: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 2044

        inet 192.168.2.73  netmask 255.255.255.0  broadcast 192.168.2.255



$ cat /proc/driver/nvidia-fs/peer_distance  | grep 0000:be:00.0 | grep network

0000:be:00.0    0000:58:00.1    138     0       network
0000:be:00.0    0000:58:00.0    138     0       network
0000:be:00.0    0000:86:00.1    134     0       network
0000:be:00.0    0000:35:00.0    138     0       network
0000:be:00.0    0000:5d:00.0    138     0       network
0000:be:00.0    0000:bd:00.0    3       0       network
0000:be:00.0    0000:b8:00.1    7       30210269        network (ib4) (chosen peer)
0000:be:00.0    0000:06:00.0    134     0       network
0000:be:00.0    0000:0c:00.1    134     0       network
0000:be:00.0    0000:e6:00.0    138     0       network
0000:be:00.0    0000:3a:00.1    138     0       network
0000:be:00.0    0000:e1:00.0    138     0       network
0000:be:00.0    0000:bd:00.1    3       4082933 network (ib5) (best peer)
0000:be:00.0    0000:e6:00.1    138     0       network
0000:be:00.0    0000:86:00.0    134     0       network
0000:be:00.0    0000:35:00.1    138     0       network
0000:be:00.0    0000:e1:00.1    138     0       network
0000:be:00.0    0000:0c:00.0    134     0       network
0000:be:00.0    0000:b8:00.0    7       0       network
0000:be:00.0    0000:5d:00.1    138     0       network
0000:be:00.0    0000:3a:00.0    138     0       network

这是一个最佳 LNet 配置的示例

[root@ai200-090a-vm00 ~]# lnetctl net show
net:
    - net type: lo
      local NI(s):
        - nid: 0@lo
          status: up
    - net type: o2ib
      local NI(s):
        - nid: 192.168.1.61@o2ib
          status: up
          interfaces:
              0: ib0
    - net type: o2ib1
      local NI(s):
        - nid: 192.168.2.61@o2ib1
          status: up
          interfaces:
              0: ib1

10. 了解 EXAScaler 文件系统性能#

根据主机通道适配器 (HCA)(通常称为 NIC)的类型,可以调整 LNet 的 mod 参数。您选择的 NIC 应处于正常和健康状态。

要通过挂载和运行一些基本测试来验证健康状况,请使用 lnetctl 健康统计信息,并运行以下命令

$ cat /etc/modprobe.d/lustre.conf

示例输出

options libcfs cpu_npartitions=24 cpu_pattern=""
options lnet networks="o2ib0(ib1,ib2,ib3,ib4,ib6,ib7,ib8,ib9)"
options ko2iblnd peer_credits=32 concurrent_sends=64 peer_credits_hiw=16 map_on_demand=0

10.1. osc 调优性能参数#

以下是有关调优文件系统参数的信息。

注意

要最大化吞吐量,您可以根据网络调优以下 EXAScaler 文件系统客户端参数。

  1. 运行以下命令

$ lctl get_param osc.*.max* osc.*.checksums
  1. 查看输出,例如

$ lctl get_param osc.*.max* osc.*.checksums

osc.ai400-OST0024-osc-ffff916f6533a000.max_pages_per_rpc=4096
osc.ai400-OST0024-osc-ffff916f6533a000.max_dirty_mb=512
osc.ai400-OST0024-osc-ffff916f6533a000.max_rpcs_in_flight=32
osc.ai400-OST0024-osc-ffff916f6533a000.checksums=0

要检查 llite 参数,请运行 $ lctl get_param llite.*.*

10.2. osc、mdc 和 stripesize 的其他命令#

如果正确设置了调优参数,您可以使用这些参数进行观察。

  1. 要获取 EXAScaler 文件系统客户端侧的总体统计信息,请运行以下命令

    $ lctl get_param osc.*.import
    

    注意

    该命令包括 rpc 信息。

  2. 查看输出,例如

    $ watch -d 'lctl get_param osc.*.import | grep -B 1 inflight'
        rpcs:
           inflight: 5
        rpcs:
           inflight: 33
    
  3. 要获取 EXAScaler 文件系统客户端中每个 rpc 可以传输的最大页数,请运行以下命令

    $ lctl get_param osc.*.max_pages_per_rpc
    
  4. 要从 EXAScaler 文件系统客户端获取总体 RPC 统计信息,请运行以下命令

    $ lctl set_param osc.*.rpc_stats=clear (to reset osc stats)
    $ lctl get_param osc.*.rpc_stats
    
  5. 查看输出,例如

    osc.ai200-OST0000-osc-ffff8e0b47c73800.rpc_stats=
    snapshot_time:         1589919461.185215594 (secs.nsecs)
    read RPCs in flight:  0
    write RPCs in flight: 0
    pending write pages:  0
    pending read pages:   0
    
                            read                    write
    
    pages per rpc         rpcs   % cum % |       rpcs   % cum %
    1:                14222350  77  77   |          0   0   0
    2:                       0   0  77   |          0   0   0
    4:                       0   0  77   |          0   0   0
    8:                       0   0  77   |          0   0   0
    16:                      0   0  77   |          0   0   0
    32:                      0   0  77   |          0   0   0
    64:                      0   0  77   |          0   0   0
    128:                     0   0  77   |          0   0   0
    256:               4130365  22 100   |          0   0   0
    
                            read                    write
    
    rpcs in flight        rpcs   % cum % |       rpcs   % cum %
    0:                       0   0   0   |          0   0   0
    1:                 3236263  17  17   |          0   0   0
    2:                  117001   0  18   |          0   0   0
    3:                  168119   0  19   |          0   0   0
    4:                  153295   0  20   |          0   0   0
    5:                   91598   0  20   |          0   0   0
    6:                   42476   0  20   |          0   0   0
    7:                   17578   0  20   |          0   0   0
    8:                    9454   0  20   |          0   0   0
    9:                    7611   0  20   |          0   0   0
    10:                   7772   0  20   |          0   0   0
    11:                   8914   0  21   |          0   0   0
    12:                   9350   0  21   |          0   0   0
    13:                   8559   0  21   |          0   0   0
    14:                   8734   0  21   |          0   0   0
    15:                  10784   0  21   |          0   0   0
    16:                  11386   0  21   |          0   0   0
    17:                  13148   0  21   |          0   0   0
    18:                  15473   0  21   |          0   0   0
    19:                  17619   0  21   |          0   0   0
    20:                  18851   0  21   |          0   0   0
    21:                  21853   0  21   |          0   0   0
    22:                  21236   0  21   |          0   0   0
    23:                  21588   0  22   |          0   0   0
    24:                  23859   0  22   |          0   0   0
    25:                  24049   0  22   |          0   0   0
    26:                  26232   0  22   |          0   0   0
    27:                  29853   0  22   |          0   0   0
    28:                  31992   0  22   |          0   0   0
    29:                  43626   0  22   |          0   0   0
    30:                 116116   0  23   |          0   0   0
    31:               14018326  76 100   |          0   0   0
    

要获取与客户端元数据操作相关的统计信息,请运行以下命令

注意

元数据客户端 (MDC) 是元数据服务器 (MDS) 的客户端对应部分。

$ lctl get_param mdc.*.md_stats

要获取 EXAScaler 文件系统上文件的条带布局,请运行以下命令

$ lfs getstripe /mnt/ai200

10.3. 获取配置的基于对象的磁盘数量#

要获取配置的基于对象的磁盘数量

  1. 运行以下命令

    $ lctl get_param lov.*.target_obd
    
  2. 查看输出,例如

    0: ai200-OST0000_UUID ACTIVE
    1: ai200-OST0001_UUID ACTIVE
    

10.5. 获取元数据统计信息#

要获取元数据统计信息

  1. 运行以下命令

    $ lctl get_param lmv.*.md_stats
    
  2. 查看输出,例如

    snapshot_time             1571271931.653827773 secs.nsecs
    close                     8 samples [reqs]
    create                    1 samples [reqs]
    getattr                   1 samples [reqs]
    intent_lock               81 samples[reqs]
    read_page                 3 samples [reqs]
    revalidate_lock           1 samples [reqs]
    

10.6. 检查现有挂载#

要检查 EXAScaler 文件系统中是否存在现有挂载

  1. 运行以下命令

    $ mount | grep lustre
    
  2. 查看输出,例如

    192.168.1.61@o2ib,192.168.1.62@o2ib1:/ai200 on /mnt/ai200 type lustre
    (rw,flock,lazystatfs)
    

10.7. 卸载 EXAScaler 文件系统集群#

要卸载 EXAScaler 文件系统集群,请运行以下命令

$ sudo umount /mnt/ai200

10.8. 获取 EXAScaler 文件系统统计信息摘要#

您可以获取 EXAScaler 文件系统的统计信息摘要。

有关更多信息,请参阅 Lustre 监控和统计信息指南

10.9. 在轮询模式下使用 GPUDirect 存储#

本节介绍如何将 GDS 与条带计数大于 1 的 EXAScaler 文件系统文件在轮询模式下一起使用。

当前,如果启用轮询模式,则 cuFileReadscuFileWrites 可能会返回少于请求字节数的字节。此行为符合 POSIX 标准,并且在使用条带计数大于其布局中计数的文件的时观察到。如果发生此行为,我们建议应用程序检查返回的字节并继续,直到所有数据都被消耗。您还可以将相应的 properties.poll_mode_max_size_kb,(例如 1024(KB)) 值设置为目录中可能的最低条带大小。这确保了超过此限制的 IO 大小不会被轮询。

  1. 要检查 EXAScaler 文件系统文件布局,请运行以下命令。

    $ lfs getstripe <file-path>
    
  2. 查看输出,例如

    lfs getstripe /mnt/ai200/single_stripe/md1.0.0
    /mnt/ai200/single_stripe/md1.0.0
    lmm_stripe_count:  1
    lmm_stripe_size:   1048576
    lmm_pattern:       raid0
    lmm_layout_gen:    0
    lmm_stripe_offset: 0
            obdidx           objid           objid           group
                 0            6146         0x1802                0
    

11. WekaIO 文件系统的故障排除和常见问题解答#

本节提供有关 WekaIO 文件系统的故障排除和常见问题解答信息。

11.1. 下载 WekaIO 客户端软件包#

要下载 WekaIO 客户端软件包,请运行以下命令

$ curl http://<IP of one of the WekaIO hosts' IB interface>:14000/dist/v1/install | sh

例如,$ curl http://172.16.8.1:14000/dist/v1/install | sh

11.2. 确定 WekaIO 版本是否已准备好用于 GDS#

要确定 WekaIO 版本是否已准备好用于 GDS

  1. 运行以下命令

    $ weka version
    
  2. 查看输出,例如

    * 3.6.2.5-rdma-beta
    

    注意

    当前,唯一支持 GDS 的 WekaIO FS 版本是 * 3.6.2.5-rdma-beta

11.3. 挂载 WekaIO 文件系统集群#

WekaIO 文件系统可以采用参数来为用户空间进程保留固定数量的核心。

  1. 要挂载 server_ip 172.16.8.1 并使用两个专用核心,请运行以下命令

    $ mkdir -p /mnt/weka
    $ sudo mount -t wekafs -o num_cores=2 -o net=ib0,net=ib1,net=ib2,net=ib3,net=ib4,net=ib5,net=ib6,net=ib7
    172.16.8.1/fs01 /mnt/weka
    
  2. 查看输出,例如

    Mounting 172.16.8.1/fs01 on /mnt/weka
    Creating weka container
    Starting container
    Waiting for container to join cluster
    Container "client" is ready (pid = 47740)
    Calling the mount command
    Mount completed successfully
    

11.4. 解决挂载失败问题#

  1. 在挂载选项中使用 IB 接口之前,请验证是否为 net=<interface> 设置了接口

    $ sudo mount -t wekafs -o num_cores=2 -o
    net=ib0,net=ib1,net=ib2,net=ib3,net=ib4,net=ib5,net=ib6,net=ib7
    172.16.8.1/fs01 /mnt/weka
    
  2. 查看输出,例如

    Mounting 172.16.8.1/fs01 on /mnt/weka
    Creating weka container
    Starting container
    Waiting for container to join cluster
    error: Container "client" has run into an error: Resources
    assignment failed: IB/MLNX network devices should have
    pre-configured IPs and ib4 has none
    
  3. 从挂载选项中删除没有网络连接的接口。

    $ ibdev2netdev
    
    mlx5_0 port 1 ==> ib0 (Up)
    mlx5_1 port 1 ==> ib1 (Up)
    mlx5_2 port 1 ==> ib2 (Up)
    mlx5_3 port 1 ==> ib3 (Up)
    mlx5_4 port 1 ==> ib4 (Down)
    mlx5_5 port 1 ==> ib5 (Down)
    mlx5_6 port 1 ==> ib6 (Up)
    mlx5_7 port 1 ==> ib7 (Up)
    mlx5_8 port 1 ==> ib8 (Up)
    mlx5_9 port 1 ==> ib9 (Up)
    

11.5. 解决 WekaIO 双核 100% 使用率问题#

如果您有两个核心,并且遇到 100% CPU 使用率

  1. 运行以下命令。

    $ top
    
  2. 查看输出,例如

    PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND
    54816 root      20   0 11.639g 1.452g 392440 R  94.4  0.1 781:06.06 wekanode
    54825 root      20   0 11.639g 1.452g 392440 R  94.4  0.1 782:00.32 wekanode
    

    当指定 num_cores=2 参数时,两个核心用于 WekaIO FE 网络的用户模式轮询驱动程序。此过程提高了延迟和性能。有关更多信息,请参阅 WekaIO 文档

11.6. 检查 Weka 文件系统中是否存在现有挂载#

要检查 WekaIO 文件系统中是否存在现有挂载

  1. 运行以下命令

    $ mount | grep wekafs
    
  2. 查看输出,例如

    172.16.8.1/fs01 on /mnt/weka type wekafs (
    rw,relatime,writecache,inode_bits=auto,dentry_max_age_positive=1000,
    dentry_max_age_negative=0)
    

11.7. 检查 WekaIO 文件系统状态摘要#

要检查 WekaIO 文件系统状态摘要。

  1. 运行以下命令

    $ weka status
    
  2. 查看输出,例如

    WekaIO v3.6.2.5-rdma-beta (CLI build 3.6.2.5-rdma-beta)
           cluster: Nvidia (e4a4e227-41d0-47e5-aa70-b50688b31f40)
            status: OK (12 backends UP, 72 drives UP)
        protection: 8+2
         hot spare: 2 failure domains (62.84 TiB)
     drive storage: 62.84 TiB total, 819.19 MiB unprovisioned
             cloud: connected
           license: Unlicensed
    
         io status: STARTED 1 day ago (1584 buckets UP, 228 io-nodes UP)
        link layer: InfiniBand
           clients: 1 connected
             reads: 61.54 GiB/s (63019 IO/s)
            writes: 0 B/s (0 IO/s)
        operations: 63019 ops/s
            alerts: 3 active alerts, use `Wekaalerts` to list them
    

11.8. 显示 WekaIO 文件系统统计信息摘要#

要显示 WekaIO 文件系统状态摘要

  1. 运行以下命令。

    $ cat /proc/wekafs/stat
    
  2. 查看输出,例如

    IO type:      UM Average      UM Longest      KM Average      KM Longest                IO count
    --------------------------------------------------------------------------------------------------------------------------------
              total:          812 us       563448 us         9398 ns     10125660 ns               718319292 (63260 IOPS, 0 MB/sec)
             lookup:          117 us         3105 us         6485 ns       436709 ns                4079 (12041)
            readdir:            0 us            0 us            0 ns            0 ns                       0
              mknod:          231 us          453 us         3970 ns         6337 ns                      96
               open:            0 us            0 us            0 ns            0 ns                   0 (3232)
            release:            0 us            0 us            0 ns            0 ns                   0 (2720)
               read:            0 us            0 us            0 ns            0 ns                       0
              write:        18957 us       563448 us       495291 ns       920127 ns              983137 (983041)
            getattr:           10 us           10 us         6771 ns         6771 ns                   1 (9271)
            setattr:          245 us          424 us         4991 ns        48222 ns                      96
              rmdir:            0 us            0 us            0 ns            0 ns                       0
             unlink:            0 us            0 us            0 ns            0 ns                       0
             rename:            0 us            0 us            0 ns            0 ns                       0
            symlink:            0 us            0 us            0 ns            0 ns                       0
           readlink:            0 us            0 us            0 ns            0 ns                       0
           hardlink:            0 us            0 us            0 ns            0 ns                       0
             statfs:         4664 us         5072 us        38947 ns        59618 ns                       7
         SG_release:            0 us            0 us            0 ns            0 ns                       0
        SG_allocate:         1042 us         7118 us         2161 ns       110282 ns                  983072
             falloc:          349 us          472 us         4184 ns        10239 ns                      96
        atomic_open:            0 us            0 us            0 ns            0 ns                       0
              flock:            0 us            0 us            0 ns            0 ns                       0
           backcomm:            0 us            0 us            0 ns            0 ns                       0
            getroot:        19701 us        19701 us        57853 ns        57853 ns                       1
              trace:            0 us            0 us            0 ns            0 ns                       0
        jumbo alloc:            0 us            0 us            0 ns            0 ns                       0
      jumbo release:            0 us            0 us            0 ns            0 ns                       0
        jumbo write:            0 us            0 us            0 ns            0 ns                       0
         jumbo read:            0 us            0 us            0 ns            0 ns                       0
          keepalive:           46 us      1639968 us         1462 ns        38996 ns                  184255
              ioctl:          787 us        50631 us         8732 ns     10125660 ns               717328710
           setxattr:            0 us            0 us            0 ns            0 ns                       0
           getxattr:            0 us            0 us            0 ns            0 ns                       0
          listxattr:            0 us            0 us            0 ns            0 ns                       0
        removexattr:            0 us            0 us            0 ns            0 ns                       0
      setfileaccess:          130 us         3437 us         6440 ns        71036 ns                    3072
            unmount:            0 us            0 us            0 ns            0 ns                       0
    

11.9. 为什么 WekaIO 写入通过 POSIX#

对于 WekaIO 文件系统,GDS 支持基于 RDMA 的读取和写入。您可以使用 fs:weka:rdma_write_support JSON 属性在支持的 Weka 文件系统上启用写入。默认情况下,此选项处于禁用状态。如果此选项设置为 false,则写入将在内部通过系统内存暂存,并且 cuFile 库将在内部使用 pwrite POSIX 调用进行写入。

11.10. 检查 nvidia-fs.ko 对内存对等直连的支持#

要检查 nvidia-fs.ko 对内存对等直连的支持

  1. 运行以下命令

    $ lsmod | grep nvidia_fs | grep ib_core && echo "Ready for Memory Peer Direct"
    
  2. 查看输出,例如

    ib_core               319488  16
    rdma_cm,ib_ipoib,mlx4_ib,ib_srp,iw_cm,nvidia_fs,ib_iser,ib_umad,
    rdma_ucm,ib_uverbs,mlx5_ib,ib_cm,ib_ucm
    "Ready for Memory Peer Direct"
    

11.11. 检查内存对等直连统计信息#

要检查内存对等统计信息

  1. 运行以下脚本,该脚本显示内存对等直连统计信息的计数器

    list=`ls /sys/kernel/mm/memory_peers/nvidia-fs/`. for stat in $list .
    do echo  "$stat value: " $(cat /sys/kernel/mm/memory_peers/nvidia-fs/$stat). done
    
  2. 查看输出。

    num_alloc_mrs value:  1288
    num_dealloc_mrs value:  1288
    num_dereg_bytes value:  1350565888
    num_dereg_pages value:  329728
    num_free_callbacks value:  0
    num_reg_bytes value:  1350565888
    num_reg_pages value:  329728
    version value:  1.0
    

11.12. 检查 WekaIO 文件系统的相关 nvidia-fs 统计信息#

要检查 WekaIO 文件系统的相关 nvida-fs 统计信息

  1. 运行以下命令

    $ cat /proc/driver/nvidia-fs/stats | egrep -v 'Reads|Writes|Ops|Error'
    
  2. 查看输出,例如

    GDS Version: 1.0.0.80
    NVFS statistics(ver: 4.0)
    NVFS Driver(version: 2.7.49)
    
    Active Shadow-Buffer (MB): 256
    Active Process: 1
    Mmap            : n=2088 ok=2088 err=0 munmap=1832
    Bar1-map        : n=2088 ok=2088 err=0 free=1826 callbacks=6 active=256
    GPU 0000:34:00.0  uuid:12a86a5e-3002-108f-ee49-4b51266cdc07 : Registered_MB=32 Cache_MB=0 max_pinned_MB=1977
    GPU 0000:e5:00.0  uuid:4c2c6b1c-27ac-8bed-8e88-9e59a5e348b5 : Registered_MB=32 Cache_MB=0 max_pinned_MB=32
    GPU 0000:b7:00.0  uuid:b224ba5e-96d2-f793-3dfd-9caf6d4c31d8 : Registered_MB=32 Cache_MB=0 max_pinned_MB=32
    GPU 0000:39:00.0  uuid:e8fac7f5-d85d-7353-8d76-330628508052 : Registered_MB=32 Cache_MB=0 max_pinned_MB=32
    GPU 0000:5c:00.0  uuid:2b13ed25-f0ab-aedb-1f5c-326745b85176 : Registered_MB=32 Cache_MB=0 max_pinned_MB=32
    GPU 0000:e0:00.0  uuid:df46743a-9b22-30ce-6ea0-62562efaf0a2 : Registered_MB=32 Cache_MB=0 max_pinned_MB=32
    GPU 0000:bc:00.0  uuid:c4136168-2a1d-1f3f-534c-7dd725fedbff : Registered_MB=32 Cache_MB=0 max_pinned_MB=32
    GPU 0000:57:00.0  uuid:54e472f2-e4ee-18dc-f2a1-3595fa8f3d33 : Registered_MB=32 Cache_MB=0 max_pinned_MB=32
    

    注意

    读取、写入、操作和错误计数器无法通过此接口用于 WekaIO 文件系统,因此该值将为零。有关使用 Weka 状态进行读取和写入的信息,请参阅 显示 WekaIO 文件系统统计信息摘要

11.13. 进行基本 WekaIO 文件系统测试#

要进行基本 WekaIO 文件系统测试

  1. 运行以下命令

    $ /usr/local/cuda-x.y/tools/gdsio_verify  -f /mnt/weka/gdstest/tests/reg1G
    -n 1 -m 0 -s 1024 -o 0  -d 0 -t 0 -S -g 4K
    
  2. 查看输出,例如

    gpu index :0,file :/mnt/weka/gdstest/tests/reg1G, RING buffer size :0,
    gpu buffer alignment :4096, gpu buffer offset :0, file offset :0,
    io_requested :1024, bufregister :false, sync :0, nr ios :1,fsync :0,
    address = 0x564ffc5e76c0
    Data Verification Success
    

11.14. 卸载 WekaIO 文件系统集群#

要卸载 WekaIO 文件系统集群

  1. 运行以下命令。

    $ sudo umount /mnt/weka
    
  2. 查看输出,例如

    Unmounting /mnt/weka
    Calling the umount command
    umount successful, stopping and deleting client container
    Umount completed successfully
    

11.15. 验证 WekaIO 文件系统的已安装库#

下表总结了用于验证 WekaIO 文件系统的已安装库的任务和命令输出。

表 3 验证 WekaIO 文件系统的已安装库#

任务

输出

检查 WekaIO 版本。

$ weka status
WekaIO v3.6.2.5-rdma-beta (CLI build 3.6.2.5-rdma-beta)

检查是否支持 WekaFS 的 GDS。

$ gdscheck -p
[...]
     WekaFS: Supported
     Userspace RDMA: Supported
[...]

检查 MLNX_OFED 信息。

使用 ofed_info -s 检查

当前支持

MLNX_OFED_LINUX-5.1-0.6.6.0

$ ofed_info -s MLNX_OFED_LINUX-5.1-0.6.6.0:

检查 nvidia-fs.ko 驱动程序。

$ lsmod | grep nvidia_fs | grep ib_core && echo "Ready for Memory Peer Direct"

检查 libibverbs.so

$ dpkg -s libibverbs-dev
Package: libibverbs-dev
Status: install ok installed
Priority: optional
Section: libdevel
Installed-Size: 1151
Maintainer: Linux RDMA Mailing List <linux-rdma@vger.kernel.org>
Architecture: amd64
Multi-Arch: same
Source: rdma-core
Version: 47mlnx1-1.47329

11.16. 支持 WekaIO 文件系统的 GDS 配置文件更改#

默认情况下,基于 Weka RDMA 的写入配置处于禁用状态。

"fs": {
    "weka": {
        // enable/disable WekaFs rdma write
        "rdma_write_support" : false
    }
}

要支持 WekaIO 文件系统,请更改配置以添加新属性 rdma_dev_addr_list

"properties": {
    // allow compat mode,
    // this will enable use of cufile posix read/writes
    //"allow_compat_mode": true,

    "rdma_dev_addr_list": [
        "172.16.8.88" , "172.16.8.89",
        "172.16.8.90" , "172.16.8.91",
        "172.16.8.92" , "172.16.8.93",
        "172.16.8.94", "172.16.8.95"
    ]
}

11.17. 检查 WekaIO 文件系统的相关用户空间统计信息#

要检查 WekaIO 文件系统的相关用户空间统计信息,请发出以下命令

$ ./gds_stats -p <pid> -l 3 | grep GPU

有关统计信息的更多信息,请参阅 GPUDirect 存储中的用户空间 RDMA 计数器

11.18. 检查 WekaFS 支持#

如果 WekaFS 支持不存在,则可能出现以下问题

表 4 Weka 文件系统支持问题#

问题

操作

MLNX_OFED 对等直连未启用。

检查是否已安装 MLNX_OFED (ofed_info -s)。

如果在安装 MLNX_OFED 之前安装了 nvidia-fs Debian 软件包,则可能会发生此问题。当发生此问题时,请卸载并重新安装 nvidia-fs 软件包。

RDMA 设备未填充到 /etc/cufile.json 文件中。

将 IP 地址添加到 properties.rdma_dev_addr_list。当前仅支持 IPv4 地址。

配置的 RDMA 设备均未启动。

检查接口的 IB 连接。

12. 启用 IBM Spectrum Scale 对 GDS 的支持#

从 IBM Spectrum Scale 5.1.2 开始支持 GDS。

在查看 NVIDIA GDS 文档后,请参阅 IBM Spectrum Scale 5.1.2。请特别参阅《规划和安装指南》中的 GDS 部分。

有关故障排除,请参阅 https://www.ibm.com/docs/en/spectrum-scale/5.1.2?topic=troubleshooting-gpudirect-storage-issues

12.1. IBM Spectrum Scale 对 GDS 的限制#

有关 IBM Spectrum Scale 对 GDS 的限制,请参阅以下文档

https://www.ibm.com/docs/en/spectrum-scale/5.1.2?topic=architecture-gpudirect-storage-support-spectrum-scale

12.2. 检查 nvidia-fs.ko 对 Mellanox PeerDirect 的支持#

使用以下命令检查对内存对等直连的支持

$ cat /proc/driver/nvidia-fs/stats | grep -i "Mellanox PeerDirect Supported"
Mellanox PeerDirect Supported: True

在以上示例中,False 表示在安装 nvidia-fs 之前,MLNX_OFED 未安装 GPUDirect 存储支持。

检查 Mellanox PeerDirect 支持的另一种方法是通过 gdscheck -p 输出。如果已启用,您应该能够看到类似以下内容。

--Mellanox PeerDirect : Enabled

12.3. 验证 IBM Spectrum Scale 的已安装库#

可以执行以下任务(显示示例输出)以显示 IBM Spectrum Scale 的已安装库

  • 检查是否支持 IBM Spectrum Scale 的 GDS

    [~]# /usr/local/cuda/gds/tools/gdscheck -p | egrep -e "Spectrum Scale|PeerDirect|rdma_device_status"
     IBM Spectrum Scale : Supported
     --Mellanox PeerDirect : Enabled
     --rdma_device_status  : Up: 2 Down: 0
    
  • 检查 MLNX_OFED 信息

    $ ofed_info -s
    MLNX_OFED_LINUX-5.4-1.0.3.0:
    
  • 检查 nvidia-fs.ko 驱动程序

    [~]# cat /proc/driver/nvidia-fs/stats
     GDS Version: 1.0.0.82
      NVFS statistics(ver: 4.0)
      NVFS Driver(version: 2.7.49)
      Mellanox PeerDirect Supported: True
      IO stats: Disabled, peer IO stats: Disabled
      Logging level: info
    
      Active Shadow-Buffer (MiB): 0
      Active Process: 0
      Reads                           : err=0 io_state_err=0
      Sparse Reads                    : n=230 io=0 holes=0 pages=0
      Writes                          : err=0 io_state_err=237 pg-cache=0 pg-cache-fail=0 pg-cache-eio=0
      Mmap                            : n=27 ok=27 err=0 munmap=27
      Bar1-map                        : n=27 ok=27 err=0 free=27 callbacks=0 active=0
      Error                           : cpu-gpu-pages=0 sg-ext=0 dma-map=0 dma-ref=0
      Ops                             : Read=0 Write=0
      GPU 0000:2f:00.0  uuid:621f7d17-5e7d-8f79-be27-d2f4256ddd88 : Registered_MiB=0 Cache_MiB=0 max_pinned_MiB=2
    
  • 在 Ubuntu 上检查 libibverbs.so

    $ dpkg -s libibverbs-dev
    root@fscc-sr650-59:~# dpkg -s libibverbs-dev
    Package: libibverbs-dev
    Status: install ok installed
    Priority: optional
    Section: libdevel
    Installed-Size: 1428
    Maintainer: Linux RDMA Mailing List <linux-rdma@vger.kernel.org>
    Architecture: amd64
    Multi-Arch: same
    Source: rdma-core
    Version: 54mlnx1-1.54103
    
  • 在 RHEL 上检查 libibverbs.so

    []# rpm -qi libibverbs
    Name        : libibverbs
    Version     : 54mlnx1
    Release     : 1.54103
    Architecture: x86_64
    Install Date: Tue 13 Jul 2021 10:21:18 AM CEST
    Group       : System Environment/Libraries
    Size        : 535489
    License     : GPLv2 or BSD
    Signature   : DSA/SHA1, Fri 02 Jul 2021 08:14:44 PM CEST, Key ID c5ed83e26224c050
    Source RPM  : rdma-core-54mlnx1-1.54103.src.rpm
    Build Date  : Fri 02 Jul 2021 06:59:01 PM CEST
    Build Host  : c-141-24-1-005.mtl.labs.mlnx
    Relocations : (not relocatable)
    URL         : https://github.com/linux-rdma/rdma-core
    Summary     : A library and drivers for direct userspace use of RDMA (InfiniBand/iWARP/RoCE) hardware
    Description :
    libibverbs is a library that allows userspace processes to use RDMA
    "verbs" as described in the InfiniBand Architecture Specification and
    the RDMA Protocol Verbs Specification.  This includes direct hardware
    access from userspace to InfiniBand/iWARP adapters (kernel bypass) for
    fast path operations.

    Device-specific plug-in ibverbs userspace drivers are included:

- libmlx5: Mellanox ConnectX-4+ InfiniBand HCA

12.4. 检查 PeerDirect 统计信息#

要检查内存对等统计信息,请运行以下脚本

list=`ls /sys/kernel/mm/memory_peers/nvidia-fs/`; for stat in $list;do echo  "$stat value: " $(cat /sys/kernel/mm/memory_peers/nvidia-fs/$stat); done

示例输出

num_alloc_mrs value:  1288
num_dealloc_mrs value:  1288
num_dereg_bytes value:  1350565888
num_dereg_pages value:  329728
num_free_callbacks value:  0
num_reg_bytes value:  1350565888
num_reg_pages value:  32972
version value:  1.0

12.5. 检查与 IBM Spectrum Scale 相关的 nvidia-fs 统计信息#

使用以下步骤检查 IBM Spectrum Scale 文件系统的相关 nvidia-fs 统计信息。

  1. 启用 nvidia-fs 统计信息

    # echo 1 > /sys/module/nvidia_fs/parameters/rw_stats_enabled
    
  2. $ cat /proc/driver/nvidia-fs/stats

  3. 查看输出

      [~]# cat /proc/driver/nvidia-fs/stats
        GDS Version: 1.0.0.82
        NVFS statistics(ver: 4.0)
        NVFS Driver(version: 2.7.49)
        Mellanox PeerDirect Supported: True
        IO stats: Disabled, peer IO stats: Disabled
        Logging level: info
    
        Active Shadow-Buffer (MiB): 0
        Active Process: 0
        Reads                           : err=0 io_state_err=0
        Sparse Reads                    : n=230 io=0 holes=0 pages=0
        Writes                          : err=0 io_state_err=237 pg-cache=0 pg-cache-fail=0 pg-cache-eio=0
        Mmap                            : n=27 ok=27 err=0 munmap=27
        Bar1-map                        : n=27 ok=27 err=0 free=27 callbacks=0 active=0
        Error                           : cpu-gpu-pages=0 sg-ext=0 dma-map=0 dma-ref=0
        Ops                             : Read=0 Write=0
    GPU 0000:2f:00.0  uuid:621f7d17-5e7d-8f79-be27-d2f4256ddd88 : Registered_MiB=0 Cache_MiB=0 max_pinned_MiB=2
    

12.6. 每个进程的 IBM Spectrum Scale 的 GDS 用户空间统计信息#

要检查 GDS 用户空间级别的统计信息,请确保 cufile.json 中的 cufile_stats 属性设置为 3。运行以下命令以检查特定进程的用户空间统计信息

$ /usr/local/cuda-<x>.<y>/gds/tools/gds_stats -p <pid> -l 3
cuFile STATS VERSION : 4
GLOBAL STATS:
Total Files: 1
Total Read Errors : 0
Total Read Size (MiB): 7302
Read BandWidth (GiB/s): 0.691406
Avg Read Latency (us): 6486
Total Write Errors : 0
Total Write Size (MiB): 0
Write BandWidth (GiB/s): 0
Avg Write Latency (us): 0
READ-WRITE SIZE HISTOGRAM :
0-4(KiB): 0  0
4-8(KiB): 0  0
8-16(KiB): 0  0
16-32(KiB): 0  0
32-64(KiB): 0  0
64-128(KiB): 0  0
128-256(KiB): 0  0
256-512(KiB): 0  0
512-1024(KiB): 0  0
1024-2048(KiB): 0  0
2048-4096(KiB): 3651  0
4096-8192(KiB): 0  0
8192-16384(KiB): 0  0
16384-32768(KiB): 0  0
32768-65536(KiB): 0  0
65536-...(KiB): 0  0
PER_GPU STATS:
GPU 0 Read: bw=0.690716 util(%)=199 n=3651 posix=0 unalign=0 dr=0 r_sparse=0 r_inline=0 err=0 MiB=7302 Write: bw=0 util(%)=0 n=0 posix=0 unalign=0 dr=0 err=0 MiB=0 BufRegister: n=2 err=0 free=0 MiB=4
PER_GPU POOL BUFFER STATS:
PER_GPU POSIX POOL BUFFER STATS:

PER_GPU RDMA STATS:
GPU 0000:43:00.0 :   mlx5_0(130:64):Reads: 3594 Writes: 0  mlx5_1(130:64):Reads: 3708 Writes: 0
RDMA MRSTATS:
peer name   nr_mrs      mr_size(MiB)
mlx5_0      1           2
mlx5_1      1           2

在以上示例中,3954 MiB 的 IBM Spectrum Scale 读取 IO 通过 mlx5_0,而 3708 MiB 的 IBM Spectrum Scale 读取通过 mlx5_1RDMA MRSTATS 值显示 RDMA 内存注册的数量和这些注册的大小。

12.7. 支持 IBM Spectrum Scale 的 GDS 配置#

  1. 配置 DC 密钥。

    可以按以下方式配置 IBM Spectrum Scale 客户端的 DC 密钥

    • 设置环境变量 CUFILE_RDMA_DC_KEY。应将其设置为 32 位十六进制值。可以按以下示例所示进行设置

      export CUFILE_RDMA_DC_KEY = 0x11223344
      
    • cufile.json 中设置属性 rdma_dc_key。此属性是 32 位值,可以按以下示例所示进行设置

      "rdma_dc_key": "0xffeeddcc",
      

    如果环境变量和 cufile.json 都设置了该属性,则环境变量 CUFILE_RDMA_DC_KEY 将优先于 cufile.json 中设置的 rdma_dc_key 属性。

    如果以上均未设置,则配置的默认 DC 密钥为 0xffeeddcc

  2. cufile.json 中配置 IP 地址。

    应在 cufile.json 中使用要用于 IO 的 RDMA 设备的 IP 地址设置 >rdma_dev_addr_list 属性。

    "properties": {
        -------
        "rdma_dev_addr_list": [
               "172.16.8.88" , "172.16.8.89",
               "172.16.8.90" , "172.16.8.91",
               "172.16.8.92" , "172.16.8.93",
               "172.16.8.94", "172.16.8.95" ]
         }
         ---------
    }
    
  3. cufile.json 中配置 max_direct_io_size_kb 属性。

    您可以使用以下属性更改 IO 大小

    "properties": {
        -------
        "max_direct_io_size_kb" : 1024
        ---------
    }
    
  4. cufile.json 中配置 rdma_access_mask 属性。

    此属性是性能可调参数。有关此属性的最佳配置,请参阅 IBM Spectrum Scale 文档 https://www.ibm.com/docs/en/spectrum-scale/5.1.2?topic=configuring-gpudirect-storage-spectrum-scale

    "properties": {
        -------
        "rdma_access_mask": "0x1f",
        ---------
    }
    

12.8. 回退到兼容模式的场景#

在某些情况下,无论 cufile.json 中的 allow_compat_mode 属性的值如何,都将导致 IBM Spectrum Scale IO 通过兼容模式。有关这些情况的完整列表,请参阅 http://www.ibm.com/support/pages/node/6444075

12.9. GDS 对 IBM Spectrum Scale 的限制#

当前,每个 GPU 缓冲区的 RDMA 内存注册最大数量为 16。因此,每个 GPU 缓冲区可通过 RDMA 注册的最大内存大小为 16 * max_direct_to_size_kb(在 cufile.json 中设置)。任何超出此偏移量的 IBM Spectrum Scale 的 GDS IO 都将通过反弹缓冲区,并且可能会对性能产生影响。

13. NetApp E 系列 BeeGFS 与 GDS 解决方案部署#

NetApp 支持 BeeGFS 高可用性。

有关如何部署 BeeGFS 并行文件系统的信息,请参阅《BeeGFS 与 Netapp E 系列技术报告》:Netapp BeeGFS 部署。对于需要高可用性的部署,请参阅 BeeGFS 高可用性与 NetApp E 系列

13.1. Netapp BeeGFS/GPUDirect 存储和软件包要求#

BeeGFS 客户端和带有 GDS 的存储

CUDA 和 GDS 仅在 beegfs-client 主机上是必需的。BeeGFS 服务器主机没有 CUDA 或 GPUDirect 存储要求。

13.2. BeeGFS 客户端 GDS 配置#

安装 beegfs-client 后,需要为 RDMA 和 GDS 配置客户端构建。

  1. 编辑 /etc/beegfs/beegfs-client-autobuild.conf。将文件的第 57 行更改为

    buildArgs=-j8 NVFS_H_PATH=/usr/src/mlnx-ofed-kernel-5.4/drivers/nvme/host OFED_INCLUDE_PATH=/usr/src/ofa_kernel/default/include
    

    这应全部在同一行上。

  2. 重建 beegfs-client

    sudo /etc/init.d/beegfs-client rebuild
    

13.3. 客户端上的 GPU/HCA 拓扑 - DGX-A100 和 OSS 服务器客户端服务器#

客户端服务器

ibdev

netdev

IP

GPU

Numa

OSS

目标

挂载点

mlx5_4

ibp97s0f0

10.10.0.177/24

0,1,2,3

0

meta 1

5,6,7,8

/mnt/beegfs/

mlx5_5

ibp97s0f1

10.10.1.177/24

0,1,2,3

0

meta 1

5,6,7,8

/mnt/beegfs/

mlx5_10

ibp225s0f0

10.10.2.157/24

4,5,6,7

4

meta 2

1,2,3,4

/mnt/beegfs/

mlx5_11

ibp225s0f1

10.10.3.157/24

4,5,6,7

4

meta 2

1,2,3,4

/mnt/beegfs/

OSS 服务器

OSS

ID

IP

Numa

meta01-numa0-1

1001

10.10.0.131:8003

0

meta01-numa1-2

1002

10.10.1.131:8004

1

meta02-numa0-1

2001

10.10.2.132:8003

0

meta02-numa1-2

2002

10.10.3.132:8004

1

13.4. 验证设置#

要验证设置,请在任何客户端上运行以下命令

13.4.1. 列出管理节点#

root@dgxa100-b:/sys/class# beegfs-ctl --listnodes --nodetype=management --details
meta-02.cpoc.local [ID: 1]
Ports: UDP: 8008; TCP: 8008
Interfaces: em3(TCP)

13.4.2. 列出元数据节点#

root@dgxa100-b:/sys/class# beegfs-ctl --listnodes --nodetype=meta -details

meta01-numa0-1-meta [ID: 1101]
   Ports: UDP: 8005; TCP: 8005
   Interfaces: ib0:net1(RDMA) ib0:net1(TCP)
meta01-numa1-2-meta [ID: 1102]
   Ports: UDP: 8006; TCP: 8006
   Interfaces: ib2:net3(RDMA) ib2:net3(TCP)
meta02-numa0-1-meta [ID: 2101]
   Ports: UDP: 8005; TCP: 8005
   Interfaces: ib0:net0(RDMA) ib0:net0(TCP)
meta02-numa1-2-meta [ID: 2102]
   Ports: UDP: 8006; TCP: 8006
   Interfaces: ib2:net2(RDMA) ib2:net2(TCP)
Number of nodes: 4
Root: 2101

13.4.3. 列出存储节点#

root@dgxa100-b:/sys/class# beegfs-ctl --listnodes --nodetype=storage -details

meta01-numa0-1 [ID: 1001]
   Ports: UDP: 8003; TCP: 8003
   Interfaces: ib0:net1(RDMA) ib0:net1(TCP)
meta01-numa1-2 [ID: 1002]
   Ports: UDP: 8004; TCP: 8004
   Interfaces: ib2:net3(RDMA) ib2:net3(TCP)
meta02-numa0-1 [ID: 2001]
   Ports: UDP: 8003; TCP: 8003
   Interfaces: ib0:net0(RDMA) ib0:net0(TCP)
meta02-numa1-2 [ID: 2002]
   Ports: UDP: 8004; TCP: 8004
   Interfaces: ib2:net2(RDMA) ib2:net2(TCP)
Number of nodes: 4

13.4.4. 列出客户端节点#

root@dgxa100-b:/sys/class# beegfs-ctl --listnodes --nodetype=client --details
B4330-6161F689-dgxa100-b [ID: 11]
   Ports: UDP: 8004; TCP: 0
 Interfaces: ibp97s0f0(RDMA) ibp97s0f0(TCP) ibp97s0f1(TCP) ibp97s0f1(RDMA) ibp225s0f0(TCP)
        ibp225s0f0(RDMA) ibp225s0f1(TCP) ibp225s0f1(RDMA)

13.4.5. 显示客户端连接#

root@dgxa100-b:/sys/class# beegfs-net

mgmt_nodes
=============
meta-02.cpoc.local [ID: 1]
   Connections: TCP: 1 (192.168.0.132:8008);

meta_nodes
=============
meta01-numa0-1-meta [ID: 1101]
   Connections: RDMA: 1 (10.10.1.131:8005);
meta01-numa1-2-meta [ID: 1102]
   Connections: RDMA: 1 (10.10.3.131:8006);
meta02-numa0-1-meta [ID: 2101]
   Connections: RDMA: 1 (10.10.0.132:8005);
meta02-numa1-2-meta [ID: 2102]
   Connections: RDMA: 1 (10.10.2.132:8006);

storage_nodes
=============
meta01-numa0-1 [ID: 1001]
   Connections: RDMA: 8 (10.10.1.131:8003);
meta01-numa1-2 [ID: 1002]
   Connections: RDMA: 8 (10.10.3.131:8004);
meta02-numa0-1 [ID: 2001]
   Connections: RDMA: 16 (10.10.0.132:8003);
meta02-numa1-2 [ID: 2002]
   Connections: RDMA: 8 (10.10.2.132:8004);

13.4.6. 验证与不同服务的连接#

root@dgxa100-b:/sys/class# beegfs-check-servers

Management
==========
meta-02.cpoc.local [ID: 1]: reachable at 192.168.0.132:8008 (protocol: TCP)

Metadata
==========
meta01-numa0-1-meta [ID: 1101]: reachable at 10.10.1.131:8005 (protocol: TCP)
meta01-numa1-2-meta [ID: 1102]: reachable at 10.10.3.131:8006 (protocol: TCP)
meta02-numa0-1-meta [ID: 2101]: reachable at 10.10.0.132:8005 (protocol: TCP)
meta02-numa1-2-meta [ID: 2102]: reachable at 10.10.2.132:8006 (protocol: TCP)

Storage
==========
meta01-numa0-1 [ID: 1001]: reachable at 10.10.1.131:8003 (protocol: TCP)
meta01-numa1-2 [ID: 1002]: reachable at 10.10.3.131:8004 (protocol: TCP)
meta02-numa0-1 [ID: 2001]: reachable at 10.10.0.132:8003 (protocol: TCP)
meta02-numa1-2 [ID: 2002]: reachable at 10.10.2.132:8004 (protocol: TCP)

13.4.7. 列出存储池#

在此示例中,我们使用了默认挂载点

root@dgxa100-b:/sys/class# sudo beegfs-ctl -liststoragepools

Pool ID   Pool Description                      Targets                 Buddy Groups
======= ================== ============================ ============================
      1            Default              1,2,3,4,5,6,7,8

13.4.8. 显示存储和元数据目标上的可用空间和 inodes#

root@dgxa100-b:/sys/class# beegfs-df

METADATA SERVERS:
TargetID   Cap. Pool        Total         Free    %      ITotal       IFree    %
========   =========        =====         ====    =      ======       =====    =
    1101      normal     573.3GiB     572.9GiB 100%      401.1M      401.0M 100%
    1102      normal     573.3GiB     572.9GiB 100%      401.1M      401.0M 100%
    2101      normal     573.3GiB     572.9GiB 100%      401.1M      401.0M 100%
    2102      normal     573.3GiB     572.9GiB 100%      401.1M      401.0M 100%

STORAGE TARGETS:
TargetID   Cap. Pool        Total         Free    %      ITotal       IFree    %
========   =========        =====         ====    =      ======       =====    =
       1      normal    2574.7GiB    1470.8GiB  57%      270.1M      270.1M 100%
       2      normal    2574.7GiB    1404.0GiB  55%      270.1M      270.1M 100%
       3      normal    2574.7GiB    1265.5GiB  49%      270.1M      270.1M 100%
       4      normal    2574.7GiB    1278.5GiB  50%      270.1M      270.1M 100%
       5      normal    2574.7GiB    1274.0GiB  49%      270.1M      270.1M 100%
       6      normal    2574.7GiB    1342.6GiB  52%      270.1M      270.1M 100%
       7      normal    2574.7GiB    1485.3GiB  58%      270.1M      270.1M 100%
       8      normal    2574.7GiB    1481.7GiB  58%      270.1M      270.1M 100%

13.5. 测试#

13.5.1. 验证集成是否正常工作#

一旦启动了具有 GDS 支持的 beegfs-client,就可以执行基本测试以验证集成是否正常工作

root@dgxa100-b:/usr/local/cuda-11.4/gds/tools# ./gdscheck.py -p
GDS release version: 1.1.1.14
nvidia_fs version:  2.7 libcufile version: 2.9
============
ENVIRONMENT:
============
=====================
DRIVER CONFIGURATION:
=====================
NVMe               : Supported
NVMeOF             : Unsupported
SCSI               : Unsupported
ScaleFlux CSD      : Unsupported
NVMesh             : Unsupported
DDN EXAScaler      : Unsupported
IBM Spectrum Scale : Unsupported
NFS                : Unsupported
BEEGFS      : Supported
WekaFS             : Unsupported
Userspace RDMA     : Unsupported
--Mellanox PeerDirect : Disabled
--rdma library        : Not Loaded (libcufile_rdma.so)
--rdma devices        : Not configured
--rdma_device_status  : Up: 0 Down: 0
=====================
CUFILE CONFIGURATION:
=====================
properties.use_compat_mode : true
properties.gds_rdma_write_support : false
properties.use_poll_mode : false
properties.poll_mode_max_size_kb : 4
properties.max_batch_io_timeout_msecs : 5
properties.max_direct_io_size_kb : 16384
properties.max_device_cache_size_kb : 131072
properties.max_device_pinned_mem_size_kb : 33554432
properties.posix_pool_slab_size_kb : 4 1024 16384
properties.posix_pool_slab_count : 128 64 32
properties.rdma_peer_affinity_policy : RoundRobin
properties.rdma_dynamic_routing : 0
fs.generic.posix_unaligned_writes : false
fs.lustre.posix_gds_min_kb: 0
fs.beegfs.posix_gds_min_kb: 0
fs.weka.rdma_write_support: false
profile.nvtx : false
profile.cufile_stats : 0
miscellaneous.api_check_aggressive : false
=========
IOMMU: disabled
Platform verification succeeded

13.5.2. 进行基本 NetApp BeeGFS 文件系统测试#

/usr/local/cuda/gds/tools/gdsio_verify -f /mnt/beegfs/file 1g -d 0 -o 0 -s 1G -n 1 -m 1
gpu index :0, file :/mnt/beegfs/file 1g, gpu buffer alignment :0, gpu buffer offset :0, gpu devptr offset :0, file offset :0, io_requested :1073741824, io_chunk_size :1073741824, bufregister :true, sync :1, nr ios :1, fsync :0,
Data Verification Success

14. 设置和故障排除 VAST Data (NFSoRDMA+MultiPath)#

本节提供有关如何设置和排除 VAST Data (NFSoRDMA+MultiPath) 故障的信息。

14.1. 安装 MLNX_OFED 和 VAST NFSoRDMA+Multipath 软件包#

14.1.1. 客户端软件要求#

下表列出了使用 MLNX_OFED 和 VAST NFSoRDMA+Multipath 软件包的最低客户端软件要求。

表 5 最低客户端要求#

NFS 连接类型

Linux 内核

MLNX_OFED

NFSoRDMA + 多路径

支持以下内核版本

  • 4.15

  • 4.18

  • 5.4

支持以下 MLNX_OFED 版本

  • 4.6

  • 4.7

  • 5.0

  • 5.1

  • 5.3

有关最新的支持性矩阵以及客户端配置步骤和软件包下载,请参阅:https://support.vastdata.com/hc/en-us/articles/360016813140-NFSoRDMA-with-Multipath

必须安装 MLNX_OFED,VAST NFSoRDMA+Multipath 软件包才能最佳地运行。下载正确的 VAST 软件包以匹配您的内核 + MLNX_OFED 版本组合也很重要。有关如何安装具有 GDS 支持的 MLNX_OFED 的信息,请参阅 使用 nvidia-fs 的 NVMe 和 NVMeOF 支持故障排除和常见问题解答

  • 要验证 MLNX_OFED 的当前版本,请发出以下命令

    $ ofed_info -s
    MLNX_OFED_LINUX-5.3-0.6.6.01:
    
  • 要验证当前安装的 Linux 内核版本,请发出以下命令

    $ uname -r -v
    

在您验证您的系统具有正确的内核和 MLNX_OFED 组合后,您可以安装 VAST Multipath 软件包。

14.1.2. 安装 VAST Multipath 软件包#

尽管 VAST Multipath 与 NFSoRDMA 软件包已提交上游以包含在未来的内核版本中,但目前仅可从以下位置下载:https://support.vastdata.com/hc/en-us/articles/360016813140-NFSoRDMA-with-Multipath

请务必下载基于您的内核和 MLNX_OFED 版本的正确 .deb 文件。

  1. 安装 VAST NFSoRDMA+Multipath 软件包

    $ sudo apt-get install mlnx-nfsrdma-*.deb
    
  2. 生成新的 initramfs 镜像

    $ sudo update-initramfs -u -k `uname -r`
    
  3. 验证软件包已安装,并且版本是您期望的数字

    $ dpkg -l | grep mlnx-nfsrdma
    ii  mlnx-nfsrdma-dkms         5.3-OFED.5.1.0.6.6.0      all  DKMS support for NFS RDMA kernel module
    
  4. 重新启动主机并运行以下命令以验证是否加载了正确的版本

    注意

    每个命令显示的版本应匹配。

    $ cat /sys/module/sunrpc/srcversion
    4CC8389C7889F82F5A59269
    $ modinfo sunrpc | grep srcversion
    srcversion:     4CC8389C7889F82F5A59269
    

14.2. 设置网络#

本节提供有关如何为 GDS 设置 VAST 客户端网络的信息。

为了确保在使用 GDS 的同时获得最佳的 GPU 到存储性能,您需要以平衡的方式配置 VAST 和客户端网络。

14.2.1. VAST 网络配置#

VAST 是一种多节点架构。每个节点都有多个高速 (IB-HDR100 或 100GbE) 接口,可以托管面向客户端的虚拟 IP。有关更多信息,请参阅 VAST - 管理虚拟 IP (VIP) 池

这是典型的工作流程

  1. 将 VAST 节点数 * 2(每个接口一个)。

  2. 使用生成的 IP 计数创建 VIP 池。

  3. 将 VAST-VIP 池放置在与客户端相同的 IP 子网上。

14.2.2. 客户端网络配置#

以下是有关客户端网络配置的信息。

通常,GPU 优化的客户端(例如 NVIDIA DGX-2 和 DGX-A100)配置有多个高速网络接口卡 (NIC)。在以下示例中,系统包含 8 个单独的 NIC,这些 NIC 被选择用于优化 NIC –>GPU 和 NIC –>CPU 带宽的平衡。

$ sudo ibdev2netdev
mlx5_0 port 1 ==> ibp12s0 (Up)
mlx5_1 port 1 ==> ibp18s0 (Up)
mlx5_10 port 1 ==> ibp225s0f0 (Down)
mlx5_11 port 1 ==> ibp225s0f1 (Down)
mlx5_2 port 1 ==> ibp75s0 (Up)
mlx5_3 port 1 ==> ibp84s0 (Up)
mlx5_4 port 1 ==> ibp97s0f0 (Down)
mlx5_5 port 1 ==> ibp97s0f1 (Down)
mlx5_6 port 1 ==> ibp141s0 (Up)
mlx5_7 port 1 ==> ibp148s0 (Up)
mlx5_8 port 1 ==> ibp186s0 (Up)
mlx5_9 port 1 ==> ibp202s0 (Up)

并非所有接口都已连接,这是为了确保最佳带宽。

当使用上述 VAST NFSoRDAM+Multipath 软件包时,建议为同一子网上的每个接口分配静态 IP,这也应与 VAST VIP 池上配置的子网匹配。如果将 GDS 与 NVIDIA DGX-A100 一起使用,则只需要一个简单的 netplan,例如

ibp12s0:
  addresses: [172.16.0.17/24]
  dhcp4: no
ibp141s0:
  addresses: [172.16.0.18/24]
  dhcp4: no
ibp148s0:
  addresses: [172.16.0.19/24]
  dhcp4: no

但是,如果您使用的是其他系统或非 GDS 代码,则需要应用以下代码以确保使用正确的接口从客户端 - > VAST 遍历。

注意

请参阅以下示例中每个接口的 routes 部分。

$ cat /etc/netplan/01-netcfg.yaml
network:
  version: 2
  renderer: networkd
  ethernets:
    enp226s0:
      dhcp4: yes
    ibp12s0:
      addresses: [172.16.0.25/24]
      dhcp6: no
      routes:
         - to: 172.16.0.0/24
           via: 172.16.0.25
           table: 101
      routing-policy:
          - from: 172.16.0.25
           table: 101
    ibp18s0:
      addresses: [172.16.0.26/24]
      dhcp4: no
      routes:
         - to: 172.16.0.0/24
           via: 172.16.0.26
           table: 102
      routing-policy:
          - from: 172.16.0.26
           table: 102
    ibp75s0:
      addresses: [172.16.0.27/24]
      dhcp4: no
      routes:
         - to: 172.16.0.0/24
           via: 172.16.0.27
           table: 103
      routing-policy:
          - from: 172.16.0.27
           table: 103
    ibp84s0:
      addresses: [172.16.0.28/24]
      dhcp4: no
      routes:
         - to: 172.16.0.0/24
           via: 172.16.0.28
           table: 104
      routing-policy:
          - from: 172.16.0.28
           table: 104
    ibp141s0:
      addresses: [172.16.0.29/24]
      dhcp4: no
      routes:
         - to: 172.16.0.0/24
           via: 172.16.0.29
           table: 105
      routing-policy:
          - from: 172.16.0.29
           table: 105
    ibp148s0:
      addresses: [172.16.0.30/24]
      dhcp4: no
      routes:
         - to: 172.16.0.0/24
           via: 172.16.0.30
           table: 106
      routing-policy:
          - from: 172.16.0.30
           table: 106
    ibp186s0:
      addresses: [172.16.0.31/24]
      dhcp4: no
      routes:
         - to: 172.16.0.0/24
           via: 172.16.0.31
           table: 107
      routing-policy:
          - from: 172.16.0.31
           table: 107
    ibp202s0:
      addresses: [172.16.0.32/24]
      dhcp4: no
      routes:
         - to: 172.16.0.0/24
           via: 172.16.0.32
           table: 108
      routing-policy:
          - from: 172.16.0.32
           table: 108

在对 netplan 进行更改后,在发出以下命令之前,请确保您具有到客户端的 IPMI/控制台连接

$ sudo netplan apply

14.2.3. 验证网络连接#

一旦应用了正确的 netplan,请使用 ping 循环验证所有客户端接口和所有 VAST-VIP 之间的连接

# Replace with appropriate interface names

$ export IFACES="ibp12s0 ibp18s0 ibp75s0 ibp84s0 ibp141s0 ibp148s0 ibp186s0 ibp202s0"
# replace with appropriate VAST-VIPs

$ export VIPS=$(echo 172.16.0.{101..116})

$ echo "starting pingtest" > pingtest.log

$ for i in $IFACES;do for v in $VIPS; do echo $i >> pingtest.log; ping -c 1 $v -W 0.2 -I $i|grep loss >> pingtest.log;done;done;

# Verify no failures:
$ grep '100%' pingtest.log

您还应验证是否满足以下条件之一

  • 所有客户端接口都直接连接到与 VAST 相同的 IB 交换机。

  • 客户端交换机和连接到 VAST 的交换机之间有足够的交换机间链路 (ISL)。

要验证当前的 IB 交换机拓扑,请发出以下命令

$ sudo ibnetdiscover
<output trimmed>

[37] "H-b8599f0300c3f4cb"[1](b8599f0300c3f4cb) # "vastraplab-cn1 HCA-2" lid 55 2xHDR  # <-- example of Vast-Node

[43] "S-b8599f0300e361f2"[43]           # "MF0;RL-QM87-C20-U33:MQM8700/U1" lid 1 4xHDR # <-- example of ISL

[67] "H-1c34da030073c27e"[1](1c34da030073c27e) # "rl-dgxa-c21-u19 mlx5_9" lid 23 4xHDR # <-- example of client

14.3. 挂载 VAST NFS#

要充分利用可用的 VAST VIP,您必须通过发出以下命令来挂载文件系统

$ sudo mount -o proto=rdma,port=20049,vers=3 \

-o noidlexprt,nconnect=40 \
-o localports=172.16.0.25-172.16.0.32 \
-o remoteports=172.16.0.101-172.16.0.140 \
172.16.0.101:/ /mnt/vast

选项包括

proto

必须指定 RDMA。

port=20049

必须指定,这是 RDMA 控制端口。

noidlexprt

不要断开空闲连接。这是为了在没有挂起的 I/O 时检测和恢复失败的连接。

nconnect

并发连接数。为了获得最佳平衡,应可被下面指定的 remoteports 数量均匀地整除。

localports

要绑定的本地端口的 IPv4 地址列表。

remoteports

要绑定的 NFS 服务器 IPv4 端口列表。

对于 localportsremoteports,您可以使用 - 分隔符指定包含范围,例如,FIRST-LAST。多个范围或单个 IP 地址可以用 ~(波浪号)分隔

14.4. 调试和监控 VAST Data#

通常,/proc 下的 mountstats 显示 xprt 统计信息。但是,VAST Multipath 软件包没有以非兼容方式使用 nfsstat 实用程序对其进行修改,而是使用额外的状态报告扩展了 mountstats,以便专门从 /sys/kernel/debug 访问。

为每个 RPC 客户端添加了 stats 节点,RPC 客户端 0 显示已完成的挂载

$ sudo cat /sys/kernel/debug/sunrpc/rpc_clnt/0/stats

添加的信息是每个 xprt 的多路径 IP 地址信息和字符串格式的 xprt 状态。

例如

xprt:   rdma 0 0 1 0 24 3 3 0 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 11 0 0 0
        172.25.1.101 -> 172.25.1.1, state: CONNECTED BOUND
xprt:   rdma 0 0 1 0 24 1 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 11 0 0 0
        172.25.1.102 -> 172.25.1.2, state: CONNECTED BOUND
xprt:   rdma 0 0 1 0 23 1 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 11 0 0 0
        172.25.1.103 -> 172.25.1.3, state: CONNECTED BOUND
xprt:   rdma 0 0 1 0 22 1 1 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 11 0 0 0
        172.25.1.104 -> 172.25.1.4, state: CONNECTED BOUND
xprt:   rdma 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
        172.25.1.101 -> 172.25.1.5, state: BOUND
xprt:   rdma 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
        172.25.1.102 -> 172.25.1.6, state: BOUND
xprt:   rdma 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
        172.25.1.103 -> 172.25.1.7, state: BOUND
xprt:   rdma 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
        172.25.1.104 -> 172.25.1.8, state: BOUND

15. 使用 Linux PCI P2PDMA 的 NVMe 支持故障排除和常见问题解答#

本节提供有关使用 Linux PCI P2PDMA 的 NVMe 支持的故障排除信息。

15.1. Linux 内核要求#

检查 Ubuntu 发行版上的 Linux 内核版本是否高于 6.2 及以上版本。

对于其他发行版,请检查是否已编译 PCI P2PDMA 功能。如果未启用 PCI P2PDMA,则可以从 MLNX_OFED 安装 GDS 特定的 NVMe 补丁,以支持使用 nvidia-fs.ko 的 GDS。

$ cat /proc/kallsyms | grep -i p2pdma_pgmap_ops
0000000000000000 d p2pdma_pgmap_ops

检查您的系统是否配备 NVIDIA GPU,且该 GPU 的架构新于或等于 NVIDIA Ampere 架构。

15.2. 支持的 GPU#

支持 A100、A40、L4、L40S 和 H100。

15.3. 设置驱动程序注册表以启用 PCI P2PDMA#

禁用多路径支持

上游驱动程序中当前未启用带有 PCI P2PDMA 的 NVMe 多路径,并且在没有专门补丁的情况下将无法工作。

$ cat /etc/modprobe.d/nvme.conf
options nvme_core multipath=N

#RH/SLES:
$ sudo dracut -f

#Ubuntu :
$ sudo update-initramfs -u -k `uname -r`
$ sudo reboot
$ cat /sys/module/nvme_core/parameters/multipath
N

pci_p2pdma 支持 ( 启用静态 BAR1 并强制禁用写合并)

在驱动程序 modprobe conf 设置中设置以下参数,使其在重启后仍然保留

$ cat /etc/modprobe.d/nvidia-temp.conf
options nvidia NVreg_RegistryDwords="RMForceStaticBar1=1;RmForceDisableIomapWC=1;"

注意

对于 Hopper 之前的 GPU(L4、L40、A100、A40),应应用以下额外的 ForceP2P=0 设置

$ cat /etc/modprobe.d/nvidia-p2pdma.conf
options nvidia
NVreg_RegistryDwords="RMForceStaticBar1=1;ForceP2P=0;RmForceDisableIomapWC=1;"

#RH/SLES:
$ sudo dracut -f

#ubuntu :
$ sudo update-initramfs -u -k `uname -r`

# reboot
$ sudo reboot

# check the settings
$ cat /proc/driver/nvidia/params | grep -i static
RegistryDwords: "RMForceStaticBar1=1;RmForceDisableIomapWC=1;"

15.4. cufile.json 设置#

将以下配置参数添加到 /etc/cufile.json 或应用程序特定的 JSON 文件中

{
    "properties": {
        "use_pci_p2pdma": true
    }
}

15.5. 验证 GDS 是否支持 P2P 模式#

/usr/local/cuda-<x>.<y>/gds/tools/gdscheck.py -p

GDS release version: 1.13.0.7
nvidia_fs version:  2.24 libcufile version: 2.12
Platform: x86_64
============
ENVIRONMENT:
============
=====================
DRIVER CONFIGURATION:
=====================
NVMe P2PDMA        : Supported
NVMe               : Supported
NVMeOF             : Unsupported

注意

如果 NVMe 同时受 PCI P2PDMA 和 nvidia-fs 支持,则 NVMe P2PDMA 模式优先。

15.6. RAID 支持#

目前,带有 PCI P2PDMA 的 GDS 不支持 RAID。

15.7. 为 GDS 挂载本地文件系统#

目前,EXT4 和 XFS 是 GDS 唯一支持的基于块设备的文件系统。由于 Direct IO 语义,EXT4 文件系统必须以设置为 data=ordered 的日志模式挂载。这必须显式包含在挂载选项中,以便库可以识别它

$ sudo mount -o data=ordered /dev/nvme0n1 /mnt

如果 EXT4 日志模式不在预期模式下,则 cuFileHandleRegister 将失败,并且相应的错误消息将记录在日志文件中。例如,在以下情况下,/mnt1 以 writeback 模式挂载,并且 GDS 返回错误

$ mount | grep /mnt1
/dev/nvme0n1p2 on /mnt1 type ext4 (rw,relatime,data=writeback)
$ ./cufile_sample_001 /mnt1/foo 0
opening file /mnt1/foo
file register error:GPUDirect Storage not supported on current file

15.8. 检查现有的 EXT4 挂载#

要检查现有的 EXT4 挂载

$ mount | grep ext4
   /dev/sda2 on / type ext4 (rw,relatime,errors=remount-ro,data=ordered)
   /dev/nvme1n1 on /mnt type ext4 (rw,relatime,data=ordered)
   /dev/nvme0n1p2 on /mnt1 type ext4 (rw,relatime,data=writeback)

注意

可以使用类似的检查来检查现有的 XFS 挂载,例如

mount | grep xfs

15.9. 检查块设备挂载的 IO 统计信息#

以下命令和部分日志显示了如何获取 IO 统计信息

$ sudo iotop
Actual DISK READ: 0.00 B/s | Actual DISK WRITE: 193.98 K/s
 TID PRIO USER DISK READ DISK WRITE SWAPIN IO> COMMAND
 881 be/3 root 0.00 B/s 15.52 K/s 0.00 % 0.01 % [jbd2/sda2-8]
 1 be/4 root 0.00 B/s 0.00 B/s 0.00 % 0.00 % init splash

15.10. 执行基本的 EXT4 文件系统测试#

要执行基本的 EXT4 文件系统测试,请发出以下命令

$ /usr/local/cuda-x.y/gds/tools/gdsio_verify -f /mnt/nvme/gdstest/tests/reg1G -n 1 -m 0 -s 1024 -o 0 -d 0 -t 0 -S -g 4K

示例输出

gpu index :0,file :/mnt/weka/gdstest/tests/reg1G, RING buffer size :0, gpu buffer alignment :4096, gpu buffer offset :0, file offset :0, io_requested :1024, bufregister :false, sync :0, nr ios :1,fsync :0,
   address = 0x564ffc5e76c0
   Data Verification Success

15.11. 卸载 EXT4 文件系统#

要卸载 EXT4 文件系统,请发出以下命令

$ sudo umount /mnt/

15.12. 块设备的 Udev 设备命名#

该库在识别基于 NVMe 的块设备时存在限制,因为它期望设备名称具有 nvme 前缀作为命名约定的一部分。

15.13. 批量 I/O 性能#

已观察到,m 个独立的批次,每个批次包含 n/m 个条目,比 1 个包含 n 个条目的批次表现出更好的性能,尤其是在基于 NVMe 的存储的情况下。

15.14. 统计信息#

没有单独的统计信息来区分 PCI P2PDMA 模式和 nvidia-fs 模式。GDS 模式统计信息对于这两种模式是通用的,应根据应用程序运行的模式进行区分。

16. 使用 nvidia-fs 的 NVMe 和 NVMeOF 支持的故障排除和常见问题解答#

本节提供有关 NVME 和 NVMeOF 支持的故障排除信息。

16.1. MLNX_OFED 要求和安装#

  • 要启用对 NVMe 和 NVMeOF 的 GDS 支持,您需要安装至少 MLNX_OFED 5.3 或更高版本。

  • 您必须安装支持 GDS 的 MLNX_OFED。

安装完成后,要使更改生效,请使用 update -initramfs 并重新启动。使用 MLNX_OFED 5.3-1.0.5.01 测试的 Linux 内核版本为 4.15.0-x 和 5.4.0-x。发出以下命令

$ sudo ./mlnxofedinstall --with-nvmf --with-nfsrdma --enable-gds --add-kernel-support --dkms

注意

从 MLNX_OFED 5.3 开始,不再需要 --enable-gds 标志。

$ sudo update-initramfs -u -k `uname -r`
$ reboot

16.2. DOCA 要求和安装#

通过 DOCA 也可获得对 NVMe 和 NVMe-oF 的 GDS 支持。如果您已通过 MLNX_OFED 安装了 GDS 补丁(如上一步所述),则不需要此步骤。要通过 DOCA 安装 GDS 补丁,请参阅 在主机上安装软件。

如果您没有受支持的 HostOS/内核,则需要从上述文档安装 DOCA 额外的软件包。之后,可以按如下方式安装 NVMe/NVMe-oF 软件包

对于 Ubuntu

$ sudo apt install doca-ofed mlnx-fw-updater mlnx-nvme-dkms
$ sudo update-initramfs -u -k `uname -r`
$ reboot

对于 RHEL

$ sudo dnf install doca-ofed mlnx-fw-updater kmod-mlnx-nvme
$ sudo dracut -f
$ reboot

16.3. 确定 NVMe 设备是否支持 GDS#

NVMe 设备必须与 GDS 兼容;设备不能具有块设备完整性功能。

对于设备完整性,Linux 块层基于主机内存中的有效负载完成元数据处理。这与标准 GDS IO 路径有所偏差,因此无法兼容这些设备。当检测到此类底层设备时,cuFile 文件注册将失败,并在 cufile.log 文件中记录相应的错误日志。

$ cat /sys/block/<nvme>/integrity/device_is_integrity_capable

16.4. GDS 中的 RAID 支持#

目前,GDS 仅支持 RAID 0。

16.5. 为 GDS 挂载本地文件系统#

目前,EXT4 和 XFS 是 GDS 唯一支持的基于块设备的文件系统。由于 Direct IO 语义,ext4 文件系统必须以设置为 data=ordered 的日志模式挂载。这必须显式包含在挂载选项中,以便库可以识别它

$ sudo mount -o data=ordered /dev/nvme0n1 /mnt

如果 EXT4 日志模式不在预期模式下,则 cuFileHandleRegister 将失败,并且相应的错误消息将记录在日志文件中。例如,在以下情况下,/mnt1 以 writeback 模式挂载,并且 GDS 返回错误

$ mount | grep /mnt1
/dev/nvme0n1p2 on /mnt1 type ext4 (rw,relatime,data=writeback)

$ ./cufile_sample_001 /mnt1/foo 0
opening file /mnt1/foo
file register error:GPUDirect Storage not supported on current file

16.6. 检查现有的 EXT4 挂载#

要检查现有的 EXT4 挂载

$ mount | grep ext4
/dev/sda2 on / type ext4 (rw,relatime,errors=remount-ro,data=ordered)
/dev/nvme1n1 on /mnt type ext4 (rw,relatime,data=ordered)
/dev/nvme0n1p2 on /mnt1 type ext4 (rw,relatime,data=writeback)

注意

可以使用类似的检查来检查现有的 XFS 挂载,例如

mount | grep xfs

16.7. 检查块设备挂载的 IO 统计信息#

以下命令和部分日志显示了如何获取 IO 统计信息

$ sudo iotop
Actual DISK READ:       0.00 B/s | Actual DISK WRITE:     193.98 K/s
  TID  PRIO  USER     DISK READ  DISK WRITE  SWAPIN     IO>    COMMAND
  881  be/3  root      0.00 B/s   15.52 K/s  0.00 %  0.01 % [jbd2/sda2-8]
    1  be/4  root      0.00 B/s    0.00 B/s  0.00 %  0.00 % init splash

16.8. GPU 亲缘性的 RAID 组配置#

从可用的 NVMe 设备创建一个 RAID 组可能不是 GDS 性能的最佳选择。您可能需要创建由与指定 GPU 具有 pci 亲缘性的设备组成的 RAID 组。这是为了防止 GPU 和 NVMe 设备之间出现跨节点 P2P 流量。

如果未强制执行亲缘性,GDS 将使用设备反弹缓冲区的内部机制,将数据从 NVMe 设备复制到最接近驱动器的中间设备,然后将数据复制回实际的 GPU。如果启用了 NVLink,这将加速这些传输。

16.9. 执行基本的 EXT4 文件系统测试#

要执行基本的 EXT4 文件系统测试,请发出以下命令

$ /usr/local/cuda-x.y/gds/tools/gdsio_verify  -f /mnt/nvme/gdstest/tests/reg1G -n 1 -m 0 -s 1024 -o 0  -d 0 -t 0 -S -g 4K

示例输出

gpu index :0,file :/mnt/weka/gdstest/tests/reg1G, RING buffer size :0, gpu buffer alignment :4096, gpu buffer offset :0, file offset :0, io_requested :1024, bufregister :false, sync :0, nr ios :1,fsync :0,
address = 0x564ffc5e76c0
Data Verification Success

16.10. 卸载 EXT4 文件系统#

要卸载 EXT4 文件系统,请发出以下命令

$ sudo umount /mnt/

16.11. 块设备的 Udev 设备命名#

该库在识别基于 NVMe 的块设备时存在限制,因为它期望设备名称具有 nvme 前缀作为命名约定的一部分。

16.12. 批量 I/O 性能#

已观察到,m 个独立的批次,每个批次包含 n/m 个条目,比 1 个包含 n 个条目的批次表现出更好的性能,尤其是在基于 NVMe 的存储的情况下。

17. 显示 GDS NVIDIA FS 驱动程序统计信息#

GDS 在 procfs 文件系统上公开 IO 统计信息。

  1. 要显示驱动程序统计信息,请运行以下命令。

    $ cat /proc/driver/nvidia-fs/stat
    
  2. 查看输出,例如

    GDS Version: 1.0.0.71
    NVFS statistics(ver: 4.0)
    NVFS Driver(version: 2:7:47)
    Mellanox PeerDirect Supported: True
    IO stats: Enabled, peer IO stats: Enabled
    Logging level: info
    
    Active Shadow-Buffer (MiB): 0
    Active Process: 0
    Reads                           : n=0 ok=0 err=0 readMiB=0 io_state_err=0
    Reads                           : Bandwidth(MiB/s)=0 Avg-Latency(usec)=0
    Sparse Reads : n=6 io=0 holes=0 pages=0
    Writes                          : n=0 ok=0 err=0 writeMiB=0 io_state_err=0
            pg-cache=0 pg-cache-fail=0 pg-cache-eio=0
    Writes                          : Bandwidth(MiB/s)=0 Avg-Latency(usec)=0
    Mmap : n=183 ok=183 err=0 munmap=183
    Bar1-map                        : n=183 ok=183 err=0 free=165 callbacks=18
            active=0
    Error                           : cpu-gpu-pages=0 sg-ext=0 dma-map=0 dma-ref=0
    Ops : Read=0 Write=0
    GPU 0000:be:00.0  uuid:87e5c586-88ed-583b-df45-fcee0f1e7917 : Registered_MiB=0 Cache_MiB=0
            max_pinned_MiB=1 cross_root_port(%)=0
    GPU 0000:e7:00.0  uuid:029faa3b-cb0d-2718-259c-6dc650c636eb : Registered_MiB=0 Cache_MiB=0
            max_pinned_MiB=1 cross_root_port(%)=0
    GPU 0000:5e:00.0  uuid:39eeb04b-1c52-81cc-d76e-53d03eb6ed32 : Registered_MiB=0 Cache_MiB=0
            max_pinned_MiB=1 cross_root_port(%)=0
    GPU 0000:57:00.0  uuid:a99a7a93-7801-5711-258b-c6aca4fe6d85 : Registered_MiB=0 Cache_MiB=0
            max_pinned_MiB=1 cross_root_port(%)=0
    GPU 0000:39:00.0  uuid:d22b0bc4-cdb1-65ac-7495-3570e5860fda : Registered_MiB=0 Cache_MiB=0
            max_pinned_MiB=1 cross_root_port(%)=0
    GPU 0000:34:00.0  uuid:e11b33d9-60f7-a721-220a-d14e5b15a52c : Registered_MiB=0 Cache_MiB=0
            max_pinned_MiB=128 cross_root_port(%)=0
    GPU 0000:b7:00.0  uuid:e8630cd2-5cb7-cab7-ef2e-66c25507c119 : Registered_MiB=0 Cache_MiB=0
            max_pinned_MiB=1 cross_root_port(%)=0
    GPU 0000:e5:00.0  uuid:b3d46477-d54f-c23f-dc12-4eb5ea172af6 : Registered_MiB=0 Cache_MiB=0
            max_pinned_MiB=1 cross_root_port(%)=0
    GPU 0000:e0:00.0  uuid:7a10c7bd-07e0-971b-a19c-61e7c185a82c : Registered_MiB=0 Cache_MiB=0
            max_pinned_MiB=1 cross_root_port(%)=0
    GPU 0000:bc:00.0  uuid:bb96783c-5a46-233a-cbce-071aeb308083 : Registered_MiB=0 Cache_MiB=0
            max_pinned_MiB=1 cross_root_port(%)=0
    GPU 0000:e2:00.0  uuid:b6565ee8-2100-7009-bcc6-a3809905620d : Registered_MiB=0 Cache_MiB=0
            max_pinned_MiB=2 cross_root_port(%)=0
    GPU 0000:5c:00.0  uuid:5527d7fb-a560-ab42-d027-20aeb5512197 : Registered_MiB=0 Cache_MiB=0
            max_pinned_MiB=1 cross_root_port(%)=0
    GPU 0000:59:00.0  uuid:bb734f6b-24ad-2f83-86c3-6ab179bce131 : Registered_MiB=0 Cache_MiB=0
            max_pinned_MiB=1 cross_root_port(%)=0
    GPU 0000:3b:00.0  uuid:0ef0b9ee-bb8f-cdae-4535-c0d790b2c663 : Registered_MiB=0 Cache_MiB=0
            max_pinned_MiB=1 cross_root_port(%)=0
    GPU 0000:b9:00.0  uuid:ad59f685-5836-c2ea-2c79-3c95bea23f0d : Registered_MiB=0 Cache_MiB=0
            max_pinned_MiB=1 cross_root_port(%)=0
    GPU 0000:36:00.0  uuid:fda65234-707b-960a-d577-18c519301848 : Registered_MiB=0 Cache_MiB=0
            max_pinned_MiB=1 cross_root_port(%)=0
    

17.1. nvidia-fs 统计信息#

下表描述了 nvidia-fs 统计信息。

表 6 NVIDIA-FS 统计信息#

类型

统计信息

描述

读取

n

读取请求的总数。

ok

成功读取请求的总数。

err

读取错误的次数。

Readmb (mb)

读入 GPU 的总数据量。

io_state_err

看到的读取错误。

某些页面可能位于页面缓存中。

读取

带宽 (MB/s)

IO 正在进行时的活动读取带宽。这是从 IO 提交到 GDS 内核驱动程序到 GDS 内核驱动程序收到 IO 完成的时间段。

没有用户空间参与。

平均延迟 (usec)

IO 正在进行时的活动读取延迟。这是从 IO 提交到 GDS 内核驱动程序到 GDS 内核驱动程序收到 IO 完成的时间段。

没有用户空间参与。

稀疏读取

n

稀疏读取请求的总数。

holes

读取期间观察到的空洞总数。

pages

跨越空洞的页面总数。

写入

n

写入请求的总数。

ok

成功写入请求的总数。

err

写入错误的次数。

Writemb (mb)

从 GPU 写入到磁盘的总数据量。

io_state_err

看到的写入错误。

某些页面可能位于页面缓存中。

pg-cache

在页面缓存中找到的写入请求总数。

pg-cache-fail

在页面缓存中找到但无法刷新的写入请求总数。

pg-cache-eio

page-cache 中找到的写入请求总数,但在多次重试后无法刷新,并且 IO 因 EIO 而失败。

写入

带宽 (MB/s)

IO 正在进行时的活动写入带宽。这是从 IO 提交到 GDS 内核驱动程序到 GDS 内核驱动程序收到 IO 完成的时间段。

没有用户空间参与。

平均延迟 (\(\mu\)sec)

IO 正在进行时的活动写入延迟。这是从 IO 提交到 GDS 内核驱动程序到 GDS 内核驱动程序收到 IO 完成的时间段。

没有用户空间参与。

Mmap

n

发出的 mmap 系统调用的总数。

ok

成功 mmap 系统调用的总数。

err

通过 mmap 系统调用观察到的错误。

munmap

发出的 munmap 总数。

Bar-map

n

GPU BAR 内存被固定的总次数。

ok

成功 GPU BAR 内存被固定的总次数。

err

在 BAR1 固定期间观察到的错误总数。

free

BAR1 内存被解除固定的总次数。

callbacks

NVIDIA 内核驱动程序调用 GDS 驱动程序回调的总次数。这在以下实例中调用

  • 当进程崩溃或被突然终止时。

  • 当在通过 cuFileBufRegister 固定的内存上调用 cudaFree,但未调用 cuFileBufDeregister 时。

active

固定的 BAR1 内存的活动数量。

(此值为总数,而不是总内存。)

Error

cpu-gpu-pages

当调用 nvfs_dma_map_sg_attrs 时,具有 CPU-GPU 页面混合的 IO 请求数。

sg-ext

由于 GPU 页面数大于 blk_nq_nr_phys_segments 而无法扩展的 Scatterlist。

dma-map

DMA 映射错误。

Ops

Read

正在进行的活动读取 IO 的总数。

Write

正在进行的活动写入 IO 的总数。

17.2. 分析每个 GPU 的统计信息#

您可以分析每个 GPU 的统计信息,以更好地了解该 GPU 中正在发生的情况。

考虑以下示例输出

GPU 0000:5e:00:0  uuid:dc87fe99-4d68-247b-b5d2-63f96d2adab1 : pinned_MB=0 cache_MB=0 max_pinned_MB=79
GPU 0000:b7:00:0  uuid:b3a6a195-d08c-09d1-bf8f-a5423c277c04 : pinned_MB=0 cache_MB=0 max_pinned_MB=76
GPU 0000:e7:00:0  uuid:7c432aed-a612-5b18-76e7-402bb48f21db : pinned_MB=0 cache_MB=0 max_pinned_MB=80
GPU 0000:57:00:0  uuid:aa871613-ee53-9a0c-a546-851d1afe4140 : pinned_MB=0 cache_MB=0 max_pinned_MB=80

在此示例输出中,0000:5e:00:0 是 GPU 的 PCI BDF,其 UUID 为 Dc87fe99-4d68-247b-b5d2-63f96d2adab1。这与可用于观察此 GPU 的 nvidia-smi 统计信息的 UUID 相同。

以下是有关统计信息的一些附加信息

  • pinned-MB 显示使用 GDS 驱动程序中的 nvidia_p2p_get_pages 固定的活动 GPU 内存,以 MB 为单位,跨所有活动进程。

  • cache_MB 显示使用 nvidia_p2p_get_pages 固定的活动 GPU 内存,但此内存被 GDS 用作内部缓存,跨所有活动进程。

  • max_pinned_MB 显示 GDS 在任何时间点在此 GPU 上跨多个进程固定的最大 GPU 内存。

    此值指示管理员可用于系统大小调整的最大 BAR 大小。

17.3. 重置 nvidia-fs 统计信息#

要重置 nvidia-fs 统计信息,请运行以下命令

$ sudo bash
$ echo 1 >/proc/driver/nvidia-fs/stats

17.4. 检查内核文件系统和存储驱动程序的对等亲缘性统计信息#

以下 proc 文件包含有关通过 nvidia-fs 回调的对等亲缘性 DMA 统计信息

  • nvidia-fs/stats

  • nvidia-fs/peer_affinity

  • nvidia-fs/peer_distance

要启用统计信息,请运行以下命令

$ sudo bash
$ echo 1 > /sys/module/nvidia_fs/parameters/peer_stats_enabled

要以常规用户身份查看合并的统计信息,请运行以下命令

$ cat /proc/driver/nvidia-fs/stats

示例输出

GDS Version: 1.0.0.71
NVFS statistics(ver: 4.0)
NVFS Driver(version: 2:7:47)
Mellanox PeerDirect Supported: True
IO stats: Enabled, peer IO stats: Enabled
Logging level: info

Active Shadow-Buffer (MiB): 0
Active Process: 0
Reads                           : n=0 ok=0 err=0 readMiB=0 io_state_err=0
Reads                           : Bandwidth(MiB/s)=0 Avg-Latency(usec)=0
Sparse Reads                    : n=6 io=0 holes=0 pages=0
Writes                          : n=0 ok=0 err=0 writeMiB=0 io_state_err=0 pg-cache=0 pg-cache-fail=0 pg-cache-eio=0
Writes                          : Bandwidth(MiB/s)=0 Avg-Latency(usec)=0
Mmap                            : n=183 ok=183 err=0 munmap=183
Bar1-map                        : n=183 ok=183 err=0 free=165 callbacks=18 active=0
Error                           : cpu-gpu-pages=0 sg-ext=0 dma-map=0 dma-ref=0
Ops                             : Read=0 Write=0
GPU 0000:be:00.0  uuid:87e5c586-88ed-583b-df45-fcee0f1e7917 : Registered_MiB=0 Cache_MiB=0 max_pinned_MiB=1 cross_root_port(%)=0
GPU 0000:e7:00.0  uuid:029faa3b-cb0d-2718-259c-6dc650c636eb : Registered_MiB=0 Cache_MiB=0 max_pinned_MiB=1 cross_root_port(%)=0
GPU 0000:5e:00.0  uuid:39eeb04b-1c52-81cc-d76e-53d03eb6ed32 : Registered_MiB=0 Cache_MiB=0 max_pinned_MiB=1 cross_root_port(%)=0
GPU 0000:57:00.0  uuid:a99a7a93-7801-5711-258b-c6aca4fe6d85 : Registered_MiB=0 Cache_MiB=0 max_pinned_MiB=1 cross_root_port(%)=0
GPU 0000:39:00.0  uuid:d22b0bc4-cdb1-65ac-7495-3570e5860fda : Registered_MiB=0 Cache_MiB=0 max_pinned_MiB=1 cross_root_port(%)=0
GPU 0000:34:00.0  uuid:e11b33d9-60f7-a721-220a-d14e5b15a52c : Registered_MiB=0 Cache_MiB=0 max_pinned_MiB=128 cross_root_port(%)=0
GPU 0000:b7:00.0  uuid:e8630cd2-5cb7-cab7-ef2e-66c25507c119 : Registered_MiB=0 Cache_MiB=0 max_pinned_MiB=1 cross_root_port(%)=0
GPU 0000:e5:00.0  uuid:b3d46477-d54f-c23f-dc12-4eb5ea172af6 : Registered_MiB=0 Cache_MiB=0 max_pinned_MiB=1 cross_root_port(%)=0
GPU 0000:e0:00.0  uuid:7a10c7bd-07e0-971b-a19c-61e7c185a82c : Registered_MiB=0 Cache_MiB=0 max_pinned_MiB=1 cross_root_port(%)=0
GPU 0000:bc:00.0  uuid:bb96783c-5a46-233a-cbce-071aeb308083 : Registered_MiB=0 Cache_MiB=0 max_pinned_MiB=1 cross_root_port(%)=0
GPU 0000:e2:00.0  uuid:b6565ee8-2100-7009-bcc6-a3809905620d : Registered_MiB=0 Cache_MiB=0 max_pinned_MiB=2 cross_root_port(%)=0
GPU 0000:5c:00.0  uuid:5527d7fb-a560-ab42-d027-20aeb5512197 : Registered_MiB=0 Cache_MiB=0 max_pinned_MiB=1 cross_root_port(%)=0
GPU 0000:59:00.0  uuid:bb734f6b-24ad-2f83-86c3-6ab179bce131 : Registered_MiB=0 Cache_MiB=0 max_pinned_MiB=1 cross_root_port(%)=0
GPU 0000:3b:00.0  uuid:0ef0b9ee-bb8f-cdae-4535-c0d790b2c663 : Registered_MiB=0 Cache_MiB=0 max_pinned_MiB=1 cross_root_port(%)=0
GPU 0000:b9:00.0  uuid:ad59f685-5836-c2ea-2c79-3c95bea23f0d : Registered_MiB=0 Cache_MiB=0 max_pinned_MiB=1 cross_root_port(%)=0
GPU 0000:36:00.0  uuid:fda65234-707b-960a-d577-18c519301848 : Registered_MiB=0 Cache_MiB=0 max_pinned_MiB=1 cross_root_port(%)=0

cross_root_port (%) 端口是通过 nvidia-fs 回调的总 DMA 流量的百分比,此值跨越 GPU 和其对等设备(如 HCA)之间的 PCIe 根端口。

  • 这可能是某些平台上吞吐量低的主要原因。

  • 这不考虑通过 cudaMemcpyDeviceToDevicecuMemcpyPeer 与指定 GPU 启动的 DMA 流量。

17.5. 检查内核文件系统和存储驱动程序的对等亲缘性使用情况#

  1. 要获取内核文件系统和存储驱动程序的对等亲缘性使用情况,请运行以下命令

    $ cat /proc/driver/nvidia-fs/peer_affinity
    
  2. 查看示例输出,例如

    GPU P2P DMA distribution based on pci-distance
    
    (last column indicates p2p via root complex)
    GPU :0000:bc:00.0 :0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
    GPU :0000:e0:00.0 :0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
    GPU :0000:e5:00.0 :0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
    GPU :0000:57:00.0 :0 0 524288 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
    GPU :0000:59:00.0 :0 0 524288 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
    GPU :0000:be:00.0 :0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
    GPU :0000:34:00.0 :0 0 1274489 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
    GPU :0000:e7:00.0 :0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
    GPU :0000:b7:00.0 :0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
    GPU :0000:36:00.0 :0 0 524288 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
    GPU :0000:3b:00.0 :0 0 524288 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
    GPU :0000:39:00.0 :0 0 524288 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
    GPU :0000:b9:00.0 :0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
    GPU :0000:5c:00.0 :0 0 524288 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
    GPU :0000:e2:00.0 :0 0 39434 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
    GPU :0000:5e:00.0 :0 0 513889 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
    

每一行代表一个 GPU 条目,列指示对等设备的等级,按升序排列。等级越低,亲缘性越好。每一列条目是指定 GPU 与属于同一等级的对等设备之间发生的 DMA 事务总数。

例如,GPU 0000:34:00.0 行通过等级 3 的对等设备具有 2621440 次 IO 操作。最后一列中的非零值表示 IO 通过根复合体路由。

以下是一些示例

运行以下命令

$ /usr/local/cuda-x.y/gds/samples /mnt/lustre/test 0
$ cat /proc/driver/nvidia-fs/stats

以下是输出

GDS Version: 1.0.0.71
NVFS statistics(ver: 4.0)
NVFS Driver(version: 2:7:47)
Mellanox PeerDirect Supported: True
IO stats: Enabled, peer IO stats: Enabled
Logging level: info


Active Shadow-Buffer (MB): 0
Active Process: 0
Reads                           : n=0 ok=0 err=0 readmb=0 io_state_err=0
Reads                           : Bandwidth(MB/s)=0 Avg-Latency(usec)=0
Sparse Reads                    : n=0 io=0 holes=0 pages=0
Writes                          : n=1 ok=1 err=0 writemb=0 io_state_err=0 pg-cache=0 pg-cache-fail=0
pg-cache-eio=0
Writes                          : Bandwidth(MB/s)=0 Avg-Latency(usec)=0
Mmap                            : n=1 ok=1 err=0 munmap=1
Bar1-map                        : n=1 ok=1 err=0 free=1 callbacks=0 active=0
Error                           : cpu-gpu-pages=0 sg-ext=0 dma-map=0
Ops                             : Read=0 Write=0
GPU 0000:34:00:0  uuid:98bb4b5c-4576-b996-3d84-4a5d778fa970 : pinned_MB=0 cache_MB=0 max_pinned_MB=0 cross_root_port(%)=100

运行以下命令

$ cat /proc/driver/nvidia-fs/peer_affinity

以下是输出

GPU P2P DMA distribution based on pci-distance

(last column indicates p2p via root complex)

GPU :0000:b7:00:0 :0 0 0 0 0 0 0 0 0 0 0 0
GPU :0000:b9:00:0 :0 0 0 0 0 0 0 0 0 0 0 0
GPU :0000:bc:00:0 :0 0 0 0 0 0 0 0 0 0 0 0
GPU :0000:be:00:0 :0 0 0 0 0 0 0 0 0 0 0 0
GPU :0000:e0:00:0 :0 0 0 0 0 0 0 0 0 0 0 0
GPU :0000:e2:00:0 :0 0 0 0 0 0 0 0 0 0 0 0
GPU :0000:e5:00:0 :0 0 0 0 0 0 0 0 0 0 0 0
GPU :0000:e7:00:0 :0 0 0 0 0 0 0 0 0 0 0 0
GPU :0000:34:00:0 :0 0 0 0 0 0 0 0 0 0 0 2
GPU :0000:36:00:0 :0 0 0 0 0 0 0 0 0 0 0 0
GPU :0000:39:00:0 :0 0 0 0 0 0 0 0 0 0 0 0
GPU :0000:3b:00:0 :0 0 0 0 0 0 0 0 0 0 0 0
GPU :0000:57:00:0 :0 0 0 0 0 0 0 0 0 0 0 0
GPU :0000:59:00:0 :0 0 0 0 0 0 0 0 0 0 0 0
GPU :0000:5c:00:0 :0 0 0 0 0 0 0 0 0 0 0 0
GPU :0000:5e:00:0 :0 0 0 0 0 0 0 0 0 0 0 0

在上面的示例中,GPU (34:00.0) 和其一个对等设备之间存在 DMA 事务。对等设备具有最高可能的等级,这表明它在 pci 距离方面离相应的 GPU 最远。

要检查流量百分比,请检查 /proc/driver/nvidia-fs/stats 中的 cross_root_ port %。在上面的第三个示例中,此值为 100%,这意味着对等流量正在通过 QPI 链路进行。

17.6. 显示 GPU 到对等设备的距离表#

peer_distance 表显示每个对等设备的设备级 IO 分布及其针对指定 GPU 的等级,它补充了基于等级的统计信息。

peer_distance 表显示每个对等设备的设备级 IO 分布及其针对指定 GPU 的等级。它补充了基于等级的统计信息。

排名按以下顺序进行

  1. 主要优先级给予 p2p 距离(高 2 字节)。

  2. 次要优先级给予设备带宽(低 2 字节)

对于跨越根端口的对等路径,会增加 p2p 距离的固定成本 (127)。这样做是为了诱导优先选择一个 CPU 根端口下的路径,而不是跨越 CPU 根端口的路径。

发出以下命令

$ cat /proc/driver/nvidia-fs/peer_distance

示例输出

gpu             peer            peerrank                p2pdist np2p    link    gen     class
0000:af:00.0    0000:86:00.0    0x820088                0x82    0       0x8     0x3     network
0000:af:00.0    0000:18:00.0    0x820088                0x82    0       0x8     0x3     nvme
0000:af:00.0    0000:86:00.1    0x820088                0x82    0       0x8     0x3     network
0000:af:00.0    0000:19:00.1    0x820088                0x82    0       0x8     0x3     network
0000:af:00.0    0000:87:00.0    0x820088                0x82    0       0x8     0x3     nvme
0000:af:00.0    0000:19:00.0    0x820088                0x82    0       0x8     0x3     network
0000:3b:00.0    0000:86:00.0    0x820088                0x82    0       0x8     0x3     network
0000:3b:00.0    0000:18:00.0    0x820088                0x82    0       0x8     0x3     nvme
0000:3b:00.0    0000:86:00.1    0x820088                0x82    0       0x8     0x3     network
0000:3b:00.0    0000:19:00.1    0x820088                0x82    0       0x8     0x3     network
0000:3b:00.0    0000:87:00.0    0x820088                0x82    0       0x8     0x3     nvme
0000:3b:00.0    0000:19:00.0    0x820088                0x82    0       0x8     0x3     network
0000:5e:00.0    0000:86:00.0    0x820088                0x82    0       0x8     0x3     network
0000:5e:00.0    0000:18:00.0    0x820088                0x82    0       0x8     0x3     nvme
0000:5e:00.0    0000:86:00.1    0x820088                0x82    0       0x8     0x3     network
0000:5e:00.0    0000:19:00.1    0x820088                0x82    0       0x8     0x3     network
0000:5e:00.0    0000:87:00.0    0x820088                0x82    0       0x8     0x3     nvme
0000:5e:00.0    0000:19:00.0    0x820088                0x82    0       0x8     0x3     network
0000:d8:00.0    0000:86:00.0    0x820088                0x82    0       0x8     0x3     network
0000:d8:00.0    0000:18:00.0    0x820088                0x82    0       0x8     0x3     nvme
0000:d8:00.0    0000:86:00.1    0x820088                0x82    0       0x8     0x3     network
0000:d8:00.0    0000:19:00.1    0x820088                0x82    0       0x8     0x3     network
0000:d8:00.0    0000:87:00.0    0x820088                0x82    0       0x8     0x3     nvme
0000:d8:00.0    0000:19:00.0    0x820088                0x82    0       0x8     0x3     network

17.7. GDSIO 工具#

GDSIO 是一个综合 IO 基准测试工具,它使用 cufile API 进行 IO。该工具位于 /usr/local/cuda-x.y/tools 目录中。有关如何使用此工具的更多信息,请运行 /usr/local/cuda-x.y/tools/gdsio -h 或查看 /usr/local/cuda-x.y/tools/README 文件中的 gdsio 部分。在下面的示例中,文件是在 ext4 文件系统上创建的。

发出以下命令

# ./gdsio -f /root/sg/test -d 0 -w 4 -s 1M -x 0 -i 4K:32K:1K -I 1

示例输出

IoType: WRITE XferType: GPUD Threads: 4 DataSetSize: 671/1024(KiB)
IOSize: 4-32-1(KiB) Throughput: 0.044269 GiB/sec, Avg_Latency:
996.094925 usecs ops: 60 total_time 0.014455 secs

此命令在名为 test 的文件上执行写入 IO (-I 1),文件大小为 1MiB (-s 1M),IO 大小在 4KiB 到 32 KiB 之间变化,步长为 1KiB (-i 4K:32K:1K)。传输使用 GDS (-x 0) 完成,使用 4 个线程 (-w 4) 在 GPU 0 (-d 0) 上。

该工具的一些附加功能包括

  • 支持在文件中的随机偏移量处进行读/写。

    gdsio 工具提供选项以在随机偏移量处对文件执行读取和写入操作。

    • 使用 -I 2 和 -I 3 选项分别以随机偏移量执行文件读取和写入操作,但随机偏移量始终为 4KiB 对齐。

      # ./gdsio -f /root/sg/test -d 0 -w 4 -s 1M -x 0 -i 4K:32K:1K -I 3
      IoType: RANDWRITE XferType: GPUD Threads: 4 DataSetSize: 706/1024(KiB) IOSize: 4-32-1(KiB) Throughput: 0.079718 GiB/sec, Avg_Latency: 590.853274 usecs ops: 44 total_time 0.008446 secs
      
    • 要以未对齐的 4KiB 偏移量执行随机读取和写入,可以将 -U 选项与 -I 0-I 1 分别用于读取和写入。

      # ./gdsio -f /root/sg/test -d 0 -w 4 -s 1M -x 0 -i 4K:32K:1K -I 1 -U
      
      IoType: RANDWRITE XferType: GPUD Threads: 4 DataSetSize: 825/1024(KiB) IOSize: 4-32-1(KiB) Throughput: 0.055666 GiB/sec, Avg_Latency: 919.112500 usecs ops: 49 total_time 0.014134 secs
      
    • 用于重复数据删除和压缩的随机缓冲区填充。

      使用 -R 选项使用随机数据填充 io 大小缓冲区 (-i)。然后,此随机数据将写入文件中的不同文件偏移量。

      # ./gdsio -f /root/sg/test -d 0 -w 4 -s 1M -x 0 -i 4K:32K:1K -I 1 -R
      
      IoType: WRITE XferType: GPUD Threads: 4 DataSetSize: 841/1024(KiB) IOSize: 4-32-1(KiB) Throughput: 0.059126 GiB/sec, Avg_Latency: 788.884580 usecs ops: 69 total_time 0.013565 secs
      
    • 使用 -F 选项将使用随机数据填充整个文件。

      # ./gdsio -f /root/sg/test -d 0 -w 4 -s 1M -x 0 -i 4K:32K:1K -I 1 -F
      
      IoType: WRITE XferType: GPUD Threads: 4 DataSetSize: 922/1024(KiB) IOSize: 4-32-1(KiB) Throughput: 0.024376 GiB/sec, Avg_Latency: 1321.104532 usecs ops: 73 total_time 0.036072 secs
      

      这对于使用重复数据删除和压缩算法以最大限度减少磁盘访问的文件系统非常有用。使用随机数据增加了这些文件系统更频繁地访问后端磁盘的可能性。

  • 可变块大小。

    要在文件上执行读取或写入操作,您可以指定块大小 (-i),它表示 IO 将以块大小长度的块执行。要检查所使用的块大小的统计信息,请使用 gds_stats 工具。确保 /etc/cufile.json 文件已将 cufile_stats 设置为 3

    # ./gds_stats -p <pid of the gdsio process> -l 3
    

    示例输出

    0-4(KiB): 0  0
    4-8(KiB): 0  17205
    8-16(KiB): 0  45859
    16-32(KiB): 0  40125
    32-64(KiB): 0  0
    64-128(KiB): 0  0
    128-256(KiB): 0  0
    256-512(KiB): 0  0
    512-1024(KiB): 0  0
    1024-2048(KiB): 0  0
    2048-4096(KiB): 0  0
    4096-8192(KiB): 0  0
    8192-16384(KiB): 0  0
    16384-32768(KiB): 0  0
    32768-65536(KiB): 0  0
    65536-...(KiB): 0  0
    

    突出显示的计数器显示,对于上面的命令,用于文件 IO 的块大小范围为 4-32 KiB。

  • 验证模式用法和限制。

    为了确保数据完整性,可以选择使用 -V 选项在验证模式下执行写入和读取 IO。这是一个示例

    # ./gdsio -V -f /root/sg/test -d 0 -w 1 -s 2G -o 0 -x 0 -k 0 -i 4K:32K:1K -I 1
    IoType: WRITE XferType: GPUD Threads: 1 DataSetSize: 2097144/2097152(KiB) IOSize: 4-32-1(KiB) Throughput: 0.074048 GiB/sec, Avg_Latency: 231.812570 usecs ops: 116513 total_time 27.009349 secs
    Verifying data
    IoType: READ XferType: GPUD Threads: 1 DataSetSize: 2097144/2097152(KiB) IOSize: 4-32-1(KiB) Throughput: 0.103465 GiB/sec, Avg_Latency: 165.900663 usecs ops: 116513 total_time 19.330184 secs
    

    以上命令将执行写入,然后执行读取验证测试。

    使用验证模式时,请记住以下几点

    • 带有验证选项 (-V) 的读取测试 (-I 0) 应与使用 -V 选项写入 (-I 1) 的文件一起使用

    • 带有验证选项 (-V) 的读取测试 (-I 2) 应与使用 -V 选项写入 (-I 3) 的文件一起使用,并使用相同的随机种子 (-k) 使用相同数量的线程、偏移量和数据大小

    • 带有验证选项 (-V) 的写入测试 (-I 1/3) 将执行写入,然后执行读取。

    • 验证模式不能在定时模式 (-T 选项) 中使用。

      如果在定时模式下使用验证模式,它将被忽略。

  • 配置文件

    GDSIO 提供了一个选项,用于配置执行 IO 所需的参数,并在配置文件中使用这些配置运行 IO。配置文件提供了执行多个作业的选项,其中每个作业都有一些不同的配置。

    配置文件具有全局参数和作业特定参数支持。例如,使用配置文件,您可以配置每个作业在 GPU 上执行,并使用不同数量的线程。全局参数(例如 IO 大小和传输模式)对于每个作业保持不变。有关更多信息,请参阅 /usr/local/cuda-x.y/tools/README/usr/local/cuda-x.y/tools/rw-sample.gdsio 文件。配置参数后,要使用配置文件执行 IO 操作,请运行以下命令

    # ./gdsio <config file name>
    

有关表格字段的列表,请参见 表格字段

17.8. 表格字段#

下表描述了 #./gdsio <config file name> 命令输出中的表格字段。

表 7 表格字段#

全局选项

描述

xfer_type

GDSIO 传输类型

  • 0 : 存储->GPU

  • 1 : 存储->CPU

  • 2 : 存储->CPU->GPU

  • 3 : 存储->CPU->GPU_ASYNC

  • 4 : 存储->PAGE_CACHE->CPU->GPU

  • 5 : 存储->GPU_ASYNC_STREAM

  • 6: 存储->GPU_BATCH

  • 7: 存储->GPU_BATCH_STREAM

rw

IO 类型,rw=read,rw=write,rw=randread,rw=randwrite

bs

块大小,例如,bs=1M,对于可变块大小,可以指定范围,例如,bs=1M:4M:1M,(1M:起始块大小,4M:结束块大小,1M:大小变化的步长)。

size

文件大小,例如,size=2G。

runtime

持续时间(秒)。

do_verify

使用 1 启用验证

skip_bufregister

跳过 cufile 缓冲区注册,在 cpu 模式下忽略。

enable_nvlinks

设置 NVlinks。

如果 p2p 流量是跨节点的,则建议使用此字段。

random_seed

使用随机种子,例如,1234。

refill_buffer

每次写入后重新填充 io 缓冲区。

fill_random

用随机数据填充请求缓冲区。

unaligned_random

使用非页面对齐的随机偏移量。

start_offset

从文件偏移量开始读取/写入。

每个作业的选项

描述

numa_node

NUMA 节点。

gpu_dev_id

GPU 设备索引(检查 nvidia-smi)。

num_threads

每个作业的 IO 线程数。

directory

文件所在的目录名称。每个线程将基于每个文件工作。

filename

单文件模式的文件名,其中线程共享同一文件。(注意:目录模式和文件模式不应在作业中混合使用)。

mem_type

要使用的内存类型。支持的值:0 - (cudaMalloc), 1 - (cuMem), 2 - (cudaMallocHost) 3 - malloc 4 - mmap。

fd_type

文件描述符模式。0 - O_DIRECT (默认)

1 - non-O_DIRECT

17.9. gdscheck 工具#

/usr/local/cuda-x.y/tools/gdscheck.py 工具用于执行 GDS 平台检查,并具有其他选项,可以使用 -h 选项找到这些选项。

$ ./gdscheck.py -h
usage: gdscheck.py [-h] [-p] [-f FILE] [-v] [-V]
GPUDirectStorage platform checker
optional arguments:
  -h, --help  show this help message and exit
  -p          gds platform check
  -f FILE     gds file check
  -v          gds version checks
  -V          gds fs checks

要执行 GDS 平台检查,请发出以下命令并期望输出采用以下格式

# ./gdscheck.py -p
GDS release version: 1.0.0.78
 nvidia_fs version:  2.7 libcufile version: 2.4
 ============
 ENVIRONMENT:
 ============
 =====================
 DRIVER CONFIGURATION:
 =====================
 NVMe               : Supported
 NVMeOF             : Unsupported
 SCSI               : Unsupported
 ScaleFlux CSD      : Unsupported
 NVMesh             : Unsupported
 DDN EXAScaler      : Supported
 IBM Spectrum Scale : Unsupported
 NFS                : Unsupported
 WekaFS             : Unsupported
 Userspace RDMA     : Unsupported
 --Mellanox PeerDirect : Enabled
 --rdma library        : Not Loaded (libcufile_rdma.so)
 --rdma devices        : Not configured
 --rdma_device_status  : Up: 0 Down: 0
 =====================
 CUFILE CONFIGURATION:
 =====================
 properties.use_compat_mode : true
 properties.gds_rdma_write_support : true
 properties.use_poll_mode : false
 properties.poll_mode_max_size_kb : 4
 properties.max_batch_io_timeout_msecs : 5
 properties.max_direct_io_size_kb : 16384
 properties.max_device_cache_size_kb : 131072
 properties.max_device_pinned_mem_size_kb : 33554432
 properties.posix_pool_slab_size_kb : 4 1024 16384
 properties.posix_pool_slab_count : 128 64 32
 properties.rdma_peer_affinity_policy : RoundRobin
 properties.rdma_dynamic_routing : 0
 fs.generic.posix_unaligned_writes : false
 fs.lustre.posix_gds_min_kb: 0
 fs.weka.rdma_write_support: false
 profile.nvtx : false
 profile.cufile_stats : 0
 miscellaneous.api_check_aggressive : false
 =========
 GPU INFO:
 =========
 GPU index 0 Tesla V100-SXM3-32GB bar:1 bar size (MiB):32768 supports GDS
 GPU index 1 Tesla V100-SXM3-32GB bar:1 bar size (MiB):32768 supports GDS
 GPU index 2 Tesla V100-SXM3-32GB bar:1 bar size (MiB):32768 supports GDS
 GPU index 3 Tesla V100-SXM3-32GB bar:1 bar size (MiB):32768 supports GDS
 GPU index 4 Tesla V100-SXM3-32GB bar:1 bar size (MiB):32768 supports GDS
 GPU index 5 Tesla V100-SXM3-32GB bar:1 bar size (MiB):32768 supports GDS
 GPU index 6 Tesla V100-SXM3-32GB bar:1 bar size (MiB):32768 supports GDS
 GPU index 7 Tesla V100-SXM3-32GB bar:1 bar size (MiB):32768 supports GDS
 GPU index 8 Tesla V100-SXM3-32GB bar:1 bar size (MiB):32768 supports GDS
 GPU index 9 Tesla V100-SXM3-32GB bar:1 bar size (MiB):32768 supports GDS
 GPU index 10 Tesla V100-SXM3-32GB bar:1 bar size (MiB):32768 supports GDS
 GPU index 11 Tesla V100-SXM3-32GB bar:1 bar size (MiB):32768 supports GDS
 GPU index 12 Tesla V100-SXM3-32GB bar:1 bar size (MiB):32768 supports GDS
 GPU index 13 Tesla V100-SXM3-32GB bar:1 bar size (MiB):32768 supports GDS
 GPU index 14 Tesla V100-SXM3-32GB bar:1 bar size (MiB):32768 supports GDS
 GPU index 15 Tesla V100-SXM3-32GB bar:1 bar size (MiB):32768 supports GDS
 ==============
 PLATFORM INFO:
 ==============
 IOMMU: disabled
 Platform verification succeeded

17.10. GPUDirect 存储的 NFS 支持#

本节提供有关 GDS 的 NFS 支持的信息。

17.10.1. 在 MLNX_OFED 5.3 或更高版本上安装带有 RDMA 支持的 Linux NFS 服务器#

要安装带有 RDMA 支持的标准 Linux 基于内核的 NFS 服务器,请完成以下步骤

注意

服务器必须具有 Mellanox connect-X4/5 NIC,并安装了 MLNX_OFED 5.3 或更高版本。

  1. 发出以下命令

    $ ofed_info -s MLNX_OFED_LINUX-5.3-1.0.5.1:
    
  2. 查看输出以确保服务器已安装。

    $ sudo apt-get install nfs-kernel-server
    $ mkfs.ext4 /dev/nvme0n1
    $ mount -o data=ordered /dev/nvme0n1 /mnt/nvme
    $ cat /etc/exports
      /mnt/nvme *(rw,async,insecure,no_root_squash,no_subtree_check)
    $ service nfs-kernel-server restart
    $ modprobe rpcrdma
    $ echo rdma 20049 > /proc/fs/nfsd/portlist
    

17.10.2. 为 NFS 客户端安装 GPUDirect 存储支持#

要安装带有 GDS 支持的 NFS 客户端,请完成以下步骤

注意

客户端必须具有 Mellanox connect-X4/5 NIC,并安装了 MLNX_OFED 5.3 或更高版本。

  1. 发出以下命令

    $ ofed_info -s MLNX_OFED_LINUX-5.3-1.0.5.0:
    
  2. 查看输出以确保支持存在。

    $ sudo apt-get install nfs-common
    $ modprobe rpcrdma
    $ mkdir -p /mnt/nfs_rdma_gds
    $ sudo mount -v -o proto=rdma,port=20049,vers=3 172.16.0.101:/ /mnt/nfs_rdma_gds
    To mount with nconnect using VAST nfs client package:
    Eg: client IB interfaces 172.16.0.17 , 172.16.0.18, 172.16.0.19, 172.16.0.20, 172.16.0.21,172.16.0.22,172.16.0.23 172.16.0.24
    $ sudo mount -v -o proto=rdma,port=20049,vers=3,nconnect=20,localports=172.16.0.17-172.16.0.24,remoteports=172.16.0.101-172.16.0.120 172.16.0.101:/ /mnt/nfs_rdma_gds
    

17.11. NFS GPUDirect 存储统计信息和调试#

可以使用用于监视 IO 的常规 Linux 工具(如 iotopnfsstat)来观察 NFS IO。

  • 要启用 NFS RPC 统计信息调试,请运行以下命令

    $ rpcdebug -v
    
  • 要观察 GDS 相关的 IO 统计信息,请运行以下命令

    $ cat /proc/driver/nvidia-fs/stats
    
  • 要确定每个进程的 GDS 统计信息,请运行以下命令

    $ /usr/local/cuda-x.y/tools/gds_stats -p <PID> -l 3
    

17.12. GPUDirect 存储 IO 行为#

本节提供有关 GDS 中的 IO 行为的信息。

17.12.1. 使用 GPUDirect 存储 Direct IO 的读取/写入原子性一致性#

在 GDS 中,max_direct_io_size_kb 属性控制 IO 单元大小,该限制以该大小发出到基础文件系统。默认情况下,此值为 16MB。这意味着从 Linux VFS 的角度来看,原子性大小限制为 max_direct_io_size_kb 大小,而不是原始请求大小。此限制存在于标准 GDS 路径和兼容模式中。

17.12.2. 以 O_APPEND 模式打开的文件写入 (cuFileWrite)#

对于以 O_APPEND 模式打开且具有并发写入器的文件,如果使用的 IO 大小大于 max_direct_io_size_kb 属性,则由于写入原子性限制,该文件可能包含来自多个写入器的交错数据。即使底层文件系统具有锁定保证,也无法阻止这种情况。

17.12.3. GPU 到 NIC 的对等亲缘性#

该库维护一个对等亲缘性表,该表是基于 pci 距离的 GPU 和平台中可用 NIC 的排名,用于 RDMA。目前,排名中的限制不考虑 NIC 的 NUMA 属性。对于不与 GPU 共享公共根端口的 NIC,即使存在与 GPU 位于同一 CPU 插槽上的 NIC,P2P 流量也可能通过 QPI 链路跨套接字路由。

17.12.4. 带有未注册缓冲区的兼容模式#

目前,在兼容模式下,带有未注册缓冲区的 IO 路径不具有最佳性能,并且在每次 cuFileRead 或 cuFileWrite 中都进行缓冲区分配和释放。

17.12.5. 使用非注册缓冲区执行未对齐写入#

对于未对齐写入,与注册缓冲区相比,使用非注册缓冲区可能无法获得最佳性能。

17.12.6. NFS 中的进程挂起#

当应用程序崩溃时,在 NFS 环境中观察到进程挂起。

17.12.7. CUDA 9 及更早版本的工具支持限制#

gdsio 二进制文件是针对 CUDA 运行时 10.1 构建的,并且依赖于 CUDA 运行时环境的版本等于或高于 10.1。否则,该工具将报告驱动程序依赖性错误。

17.13. 动态路由的 GDS 统计信息#

动态路由决策在 I/O 操作粒度上执行。GDS 用户空间统计信息包含每个 GPU 的计数器,以指示已使用动态路由路由的 I/O 数量。

表 8 cuFile 动态路由计数器#

条目

描述

dr

使用动态路由为给定 GPU 路由 I/O 的 cuFileRead/cuFileWrite 的数量。

PER_GPU POOL BUFFER STATSPER_GPU POSIX POOL BUFFER STATS 中存在现有计数器,用户可以从中推断出动态路由选择哪些 GPU 用作反弹缓冲区。

  • 平台上的 GPU(0 和 1)与 NIC 不共享相同的 PCIe 主桥

    "rdma_dev_addr_list": [ "192.168.0.12", "192.168.1.12" ],
    "rdma_dynamic_routing": true,
    "rdma_dynamic_routing_order": [ "GPU_MEM_NVLINKS", "GPU_MEM", "SYS_MEM" ]
    
    $ gds_stats -p <process id> -l 3
    
    GPU 0 Read: bw=0 util(%)=0 n=0 posix=0 unalign=0 dr=0 r_sparse=0 r_inline=0 err=0 MiB=0 Write: bw=3.37598 util(%)=532 n=6629 posix=0 unalign=0 dr=6629 err=0 MiB=6629 BufRegister: n=4 err=0 free=0 MiB=4
    GPU 1 Read: bw=0 util(%)=0 n=0 posix=0 unalign=0 dr=0 r_sparse=0 r_inline=0 err=0 MiB=0 Write: bw=3.29297 util(%)=523 n=6637 posix=0 unalign=0 dr=6637 err=0 MiB=6637 BufRegister: n=4 err=0 free=0 MiB=4
    
    PER_GPU POOL BUFFER STATS:
    GPU : 6 pool_size_MiB : 7 usage : 1/7 used_MiB : 1
    GPU : 7 pool_size_MiB : 7 usage : 0/7 used_MiB : 0
    GPU : 8 pool_size_MiB : 7 usage : 2/7 used_MiB : 2
    GPU : 9 pool_size_MiB : 7 usage : 2/7 used_MiB : 2
    
    PER_GPU POSIX POOL BUFFER STATS:
    
    PER_GPU RDMA STATS:
    GPU 0000:34:00.0 :   mlx5_3(138:48):0  mlx5_6(265:48):0
    GPU 0000:36:00.0 :   mlx5_3(138:48):0  mlx5_6(265:48):0
    GPU 0000:39:00.0 :   mlx5_3(138:48):0  mlx5_6(265:48):0
    GPU 0000:3b:00.0 :   mlx5_3(138:48):0  mlx5_6(265:48):0
    GPU 0000:57:00.0 :   mlx5_3(7:48):0  mlx5_6(265:48):0
    GPU 0000:59:00.0 :   mlx5_3(7:48):0  mlx5_6(265:48):0
    GPU 0000:5c:00.0 :   mlx5_3(3:48):3318  mlx5_6(265:48):0
    GPU 0000:5e:00.0 :   mlx5_3(3:48):3318  mlx5_6(265:48):0
    GPU 0000:b7:00.0 :   mlx5_6(3:48):3316  mlx5_3(265:48):0
    GPU 0000:b9:00.0 :   mlx5_6(3:48):3317  mlx5_3(265:48):0
    GPU 0000:bc:00.0 :   mlx5_6(7:48):0  mlx5_3(265:48):0
    GPU 0000:be:00.0 :   mlx5_6(7:48):0  mlx5_3(265:48):0
    GPU 0000:e0:00.0 :   mlx5_6(138:48):0  mlx5_3(265:48):0
    GPU 0000:e2:00.0 :   mlx5_6(138:48):0  mlx5_3(265:48):0
    GPU 0000:e5:00.0 :   mlx5_6(138:48):0  mlx5_3(265:48):0
    GPU 0000:e7:00.0 :   mlx5_6(138:48):0  mlx5_3(265:48):0
    
  • 平台配置中,GPU 与 NIC 不共享相同的 PCIe 主桥,并且 GPU 之间没有 NVLink。对于此类配置,管理员可以设置策略以使用系统内存,而不是默认的 P2P 策略。

    "rdma_dev_addr_list": [ "192.168.0.12", "192.168.1.12" ],
    "rdma_dynamic_routing": true,
    "rdma_dynamic_routing_order": [ "SYS_MEM" ]
    
    PER_GPU STATS:
    GPU 4 Read: bw=0 util(%)=0 n=0 posix=0 unalign=0 r_sparse=0 r_inline=0 err=0 MiB=0 Write: bw=1.11GiB util(%)=0 n=1023 posix=1023 unalign=1023 dr=1023 err=0 MiB=1023 BufRegister: n=0 err=0 free=0 MiB=0
    GPU 8 Read: bw=0 util(%)=0 n=0 posix=0 unalign=0 r_sparse=0 r_inline=0 err=0 MiB=0 Write: bw=1.11GiB util(%)=0 n=1023 posix=1023 unalign=1023 dr=1023 err=0 MiB=1023 BufRegister: n=0 err=0 free=0 MiB=0
    PER_GPU POSIX POOL BUFFER STATS:
    GPU 4 4(KiB) :0/0 1024(KiB) :0/1 16384(KiB) :0/0
    GPU 8 4(KiB) :0/0 1024(KiB) :1/1 16384(KiB) :0/0
    

17.13.1. 对等亲和性动态路由#

动态路由决策在 I/O 操作粒度上执行。GDS 用户空间统计信息包含每个 GPU 的计数器,以指示已使用动态路由路由的 I/O 数量。

表 9 cuFile 动态路由计数器#

条目

描述

dr

使用动态路由为给定 GPU 路由 I/O 的 cuFileRead/cuFileWrite 的数量。

PER_GPU POOL BUFFER STATSPER_GPU POSIX POOL BUFFER STATS 中存在现有计数器,用户可以从中推断出动态路由选择哪些 GPU 用作反弹缓冲区。

// "rdma_dev_addr_list": [ "192.168.4.12", "192.168.5.12", "192.168.6.12", "192.168.7.12" ],

cufile.log:
--------------
 23-02-2021 10:17:49:641 [pid=22436 tid=22436] INFO   curdma-ldbal:133 Computing GPU->NIC affinity table:
 23-02-2021 10:17:49:641 [pid=22436 tid=22436] INFO   curdma-ldbal:139 GPU: 0000:34:00.0  RDMA dev: mlx5_6 mlx5_8 mlx5_7 mlx5_9
 23-02-2021 10:17:49:641 [pid=22436 tid=22436] INFO   curdma-ldbal:139 GPU: 0000:36:00.0  RDMA dev: mlx5_6 mlx5_8 mlx5_7 mlx5_9
 23-02-2021 10:17:49:641 [pid=22436 tid=22436] INFO   curdma-ldbal:139 GPU: 0000:39:00.0  RDMA dev: mlx5_6 mlx5_8 mlx5_7 mlx5_9
 23-02-2021 10:17:49:641 [pid=22436 tid=22436] INFO   curdma-ldbal:139 GPU: 0000:3b:00.0  RDMA dev: mlx5_6 mlx5_8 mlx5_7 mlx5_9
 23-02-2021 10:17:49:641 [pid=22436 tid=22436] INFO   curdma-ldbal:139 GPU: 0000:57:00.0  RDMA dev: mlx5_6 mlx5_8 mlx5_7 mlx5_9
 23-02-2021 10:17:49:641 [pid=22436 tid=22436] INFO   curdma-ldbal:139 GPU: 0000:59:00.0  RDMA dev: mlx5_6 mlx5_8 mlx5_7 mlx5_9
 23-02-2021 10:17:49:641 [pid=22436 tid=22436] INFO   curdma-ldbal:139 GPU: 0000:5c:00.0  RDMA dev: mlx5_6 mlx5_8 mlx5_7 mlx5_9
 23-02-2021 10:17:49:641 [pid=22436 tid=22436] INFO   curdma-ldbal:139 GPU: 0000:5e:00.0  RDMA dev: mlx5_6 mlx5_8 mlx5_7 mlx5_9
 23-02-2021 10:17:49:641 [pid=22436 tid=22436] INFO   curdma-ldbal:139 GPU: 0000:b7:00.0  RDMA dev: mlx5_6
 23-02-2021 10:17:49:641 [pid=22436 tid=22436] INFO   curdma-ldbal:139 GPU: 0000:b9:00.0  RDMA dev: mlx5_6
 23-02-2021 10:17:49:641 [pid=22436 tid=22436] INFO   curdma-ldbal:139 GPU: 0000:bc:00.0  RDMA dev: mlx5_7
 23-02-2021 10:17:49:641 [pid=22436 tid=22436] INFO   curdma-ldbal:139 GPU: 0000:be:00.0  RDMA dev: mlx5_7
 23-02-2021 10:17:49:641 [pid=22436 tid=22436] INFO   curdma-ldbal:139 GPU: 0000:e0:00.0  RDMA dev: mlx5_8
 23-02-2021 10:17:49:641 [pid=22436 tid=22436] INFO   curdma-ldbal:139 GPU: 0000:e2:00.0  RDMA dev: mlx5_8
 23-02-2021 10:17:49:641 [pid=22436 tid=22436] INFO   curdma-ldbal:139 GPU: 0000:e5:00.0  RDMA dev: mlx5_9
 23-02-2021 10:17:49:641 [pid=22436 tid=22436] INFO   curdma-ldbal:139 GPU: 0000:e7:00.0  RDMA dev: mlx5_9

gds_stats 中的一个示例,显示了示例 IO 测试期间 GPU 到 NIC 的绑定

PER_GPU RDMA STATS:
   GPU 0000:34:00.0 :   mlx5_6(265:48):0  mlx5_8(265:48):0  mlx5_7(265:48):0  mlx5_9(265:48):0
   GPU 0000:36:00.0 :   mlx5_6(265:48):0  mlx5_8(265:48):0  mlx5_7(265:48):0  mlx5_9(265:48):0
   GPU 0000:39:00.0 :   mlx5_6(265:48):0  mlx5_8(265:48):0  mlx5_7(265:48):0  mlx5_9(265:48):0
   GPU 0000:3b:00.0 :   mlx5_6(265:48):0  mlx5_8(265:48):0  mlx5_7(265:48):0  mlx5_9(265:48):0
   GPU 0000:57:00.0 :   mlx5_6(265:48):0  mlx5_8(265:48):0  mlx5_7(265:48):0  mlx5_9(265:48):0
   GPU 0000:59:00.0 :   mlx5_6(265:48):0  mlx5_8(265:48):0  mlx5_7(265:48):0  mlx5_9(265:48):0
   GPU 0000:5c:00.0 :   mlx5_6(265:48):0  mlx5_8(265:48):0  mlx5_7(265:48):0  mlx5_9(265:48):0
   GPU 0000:5e:00.0 :   mlx5_6(265:48):0  mlx5_8(265:48):0  mlx5_7(265:48):0  mlx5_9(265:48):0
   GPU 0000:b7:00.0 :   mlx5_6(3:48):22918  mlx5_7(7:48):0  mlx5_8(138:48):0  mlx5_9(138:48):0
   GPU 0000:b9:00.0 :   mlx5_6(3:48):22949  mlx5_7(7:48):0  mlx5_8(138:48):0  mlx5_9(138:48):0
   GPU 0000:bc:00.0 :   mlx5_7(3:48):22945  mlx5_6(7:48):0  mlx5_8(138:48):0  mlx5_9(138:48):0
   GPU 0000:be:00.0 :   mlx5_7(3:48):22942  mlx5_6(7:48):0  mlx5_8(138:48):0  mlx5_9(138:48):0
   GPU 0000:e0:00.0 :   mlx5_8(3:48):22937  mlx5_9(7:48):0  mlx5_6(138:48):0  mlx5_7(138:48):0
   GPU 0000:e2:00.0 :   mlx5_8(3:48):22930  mlx5_9(7:48):0  mlx5_6(138:48):0  mlx5_7(138:48):0
   GPU 0000:e5:00.0 :   mlx5_9(3:48):22922  mlx5_8(7:48):0  mlx5_6(138:48):0  mlx5_7(138:48):0
   GPU 0000:e7:00.0 :   mlx5_9(3:48):22920  mlx5_8(7:48):0  mlx5_6(138:48):0  mlx5_7(138:48):0

对于基于内核的 DFS、DDN-Lustre 和 VAST-NFS,nvidia-fs 驱动程序提供回调以确定给定目标 GPU 的最佳 NIC。nvidia-fs peer_affinity 可用于跟踪端到端 IO 亲和性行为。

例如,使用 GPU_MEM_NVLINK 的路由策略,不应看到如下面的统计信息片段所示的跨端口流量

$ cat /proc/driver/nvidia-fs/peer_affinity
GPU P2P DMA distribution based on pci-distance

(last column indicates p2p via root complex)
GPU :0000:bc:00.0 :0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
GPU :0000:e0:00.0 :0 0 205305577 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
GPU :0000:e5:00.0 :0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
GPU :0000:57:00.0 :0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
GPU :0000:59:00.0 :0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
GPU :0000:be:00.0 :0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
GPU :0000:34:00.0 :0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
GPU :0000:e7:00.0 :0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
GPU :0000:b7:00.0 :0 0 205279892 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
GPU :0000:36:00.0 :0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
GPU :0000:3b:00.0 :0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
GPU :0000:39:00.0 :0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
GPU :0000:b9:00.0 :0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
GPU :0000:5c:00.0 :0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
GPU :0000:e2:00.0 :0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
GPU :0000:5e:00.0 :0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

使用 P2P 的路由策略,可以预期看到如下面的统计信息片段所示的跨端口流量

dgxuser@e155j-dgx2-c6-u04:~/ssen$ cat /proc/driver/nvidia-fs/peer_affinity
GPU P2P DMA distribution based on pci-distance

(last column indicates p2p via root complex)
GPU :0000:bc:00.0 :0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
GPU :0000:e0:00.0 :0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
GPU :0000:e5:00.0 :0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
GPU :0000:57:00.0 :0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
GPU :0000:59:00.0 :0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
GPU :0000:be:00.0 :0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
GPU :0000:34:00.0 :0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9186359
GPU :0000:e7:00.0 :0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
GPU :0000:b7:00.0 :0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
GPU :0000:36:00.0 :0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9191164
GPU :0000:3b:00.0 :0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9194318
GPU :0000:39:00.0 :0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 9188836
GPU :0000:b9:00.0 :0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
GPU :0000:5c:00.0 :0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
GPU :0000:e2:00.0 :0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
GPU :0000:5e:00.0 :0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

18. GDS 库跟踪#

GDS 库具有 USDT(静态跟踪点),可以与 Linux 工具(如 lttngbcc/bpfperf)一起使用。本节假定您熟悉这些工具。

本节中的示例显示了使用 `bcc/bpf <iovisor/bcc>`__ 跟踪工具进行跟踪。GDS 不附带这些跟踪工具。有关安装 bcc/bpf 工具的更多信息,请参阅 安装 BCC。用户必须具有 root 权限才能安装。

注意

用户还必须具有 sudo 访问权限才能使用这些工具。

18.1. 示例:显示跟踪点#

  1. 要显示跟踪点,请运行以下命令

    # ./tplist -l /usr/local/gds/lib/libcufile.so
    
  2. 查看输出,例如

    /usr/local/cuda-x.y/lib/libcufile.so cufio:cufio_px_read
    /usr/local/cuda-x.y/lib/libcufile.so cufio:cufio_rdma_read
    /usr/local/cuda-x.y/lib/libcufile.so cufio:cufio_gds_read
    /usr/local/cuda-x.y/lib/libcufile.so cufio:cufio_gds_read_async
    /usr/local/cuda-x.y/lib/libcufile.so cufio:cufio_px_write
    /usr/local/cuda-x.y/lib/libcufile.so cufio:cufio_gds_write
    /usr/local/cuda-x.y/lib/libcufile.so cufio:cufio_gds_write_async
    /usr/local/cuda-x.y/lib/libcufile.so cufio-internal:cufio-internal-write-bb
    /usr/local/cuda-x.y/lib/libcufile.so cufio-internal:cufio-internal-read-bb
    /usr/local/cuda-x.y/lib/libcufile.so cufio-internal:cufio-internal-bb-done
    /usr/local/cuda-x.y/lib/libcufile.so cufio-internal:cufio-internal-io-done
    /usr/local/cuda-x.y/lib/libcufile.so cufio-internal:cufio-internal-map
    

18.1.1. 示例:跟踪点参数#

以下是跟踪点参数的示例。

cufio_px_read

此跟踪点跟踪 POSIX IO 读取,并接受以下参数

  • 参数 1:文件描述符

  • 参数 2:文件偏移量

  • 参数 3:读取大小

  • 参数 4:GPU 缓冲区偏移量

  • 参数 5:返回值

  • 参数 6:执行 IO 的 GPU ID

cufio_rdma_read

此跟踪点跟踪通过 WEKA 文件系统的 IO 读取,并接受以下参数

  • 参数 1:文件描述符

  • 参数 2:文件偏移量

  • 参数 3:读取大小

  • 参数 4:GPU 缓冲区偏移量

  • 参数 5:返回值

  • 参数 6:执行 IO 的 GPU ID

  • 参数 7:IO 是否对 GPU 反弹缓冲区执行

cufio_rdma_write

此跟踪点跟踪通过 WEKA 文件系统的 IO 读取,并接受以下参数

  • 参数 1:文件描述符

  • 参数 2:文件偏移量

  • 参数 3:写入大小

  • 参数 4:GPU 缓冲区偏移量

  • 参数 5:返回值

  • 参数 6:执行 IO 的 GPU ID

  • 参数 7:IO 是否对 GPU 反弹缓冲区执行

cufio_gds_read

此跟踪点跟踪通过 GDS 内核驱动程序的 IO 读取,并接受以下参数

  • 参数 1:文件描述符

  • 参数 2:文件偏移量

  • 参数 3:读取大小

  • 参数 4:GPU 缓冲区偏移量

  • 参数 5:返回值

  • 参数 6:执行 IO 的 GPU ID

  • 参数 7:IO 是否对 GPU 反弹缓冲区执行

cufio_gds_read_async

此跟踪点跟踪通过 GDS 内核驱动程序的 IO 读取,并设置了轮询模式,并接受以下参数

  • 参数 1:文件描述符

  • 参数 2:文件偏移量

  • 参数 3:读取大小

  • 参数 4:GPU 缓冲区偏移量

  • 参数 5:返回值

  • 参数 6:执行 IO 的 GPU ID

  • 参数 7:IO 是否对 GPU 反弹缓冲区执行

cufio_px_write

此跟踪点跟踪 POSIX IO 写入,并接受以下参数

  • 参数 1:文件描述符

  • 参数 2:文件偏移量

  • 参数 3:写入大小

  • 参数 4:GPU 缓冲区偏移量

  • 参数 5:返回值

  • 参数 6:执行 IO 的 GPU ID

cufio_gds_write

此跟踪点跟踪通过 GDS 内核驱动程序的 IO 写入,并接受以下参数

  • 参数 1:文件描述符

  • 参数 2:文件偏移量

  • 参数 3:写入大小

  • 参数 4:GPU 缓冲区偏移量

  • 参数 5:返回值

  • 参数 6:执行 IO 的 GPU ID

  • 参数 7:IO 是否对 GPU 反弹缓冲区执行

cufio_gds_unaligned_write

如果 IO 未对齐,则此跟踪点跟踪通过 GDS 内核驱动程序的 IO 写入,并接受以下参数

  • 参数 1:文件描述符

  • 参数 2:文件偏移量

  • 参数 3:写入大小

  • 参数 4:GPU 缓冲区偏移量

  • 参数 5:返回值

  • 参数 6:执行 IO 的 GPU ID

  • 参数 7:IO 是否对 GPU 反弹缓冲区执行

cufio_gds_write_async

此跟踪点跟踪通过 GDS 内核驱动程序的 IO 写入,并设置了轮询模式,并接受以下参数

  • 参数 1:文件描述符

  • 参数 2:文件偏移量

  • 参数 3:写入大小

  • 参数 4:GPU 缓冲区偏移量

  • 参数 5:返回值

  • 参数 6:执行 IO 的 GPU ID

  • 参数 7:IO 是否对 GPU 反弹缓冲区执行

cufio-internal-write-bb

此跟踪点跟踪通过内部 GPU 反弹缓冲区的 IO 写入,并且特定于 EXAScaler 文件系统和基于块设备的文件系统。此跟踪点位于每个 IO 的热 IO 路径跟踪中,并接受以下参数

  • 参数 1:应用程序 GPU(GPU ID)

  • 参数 2:GPU 反弹缓冲区(GPU ID)

  • 参数 3:文件描述符

  • 参数 4:文件偏移量

  • 参数 5:写入大小

  • 参数 6:应用程序 GPU 缓冲区偏移量

  • 参数 7:从应用程序 GPU 缓冲区传输到目标 GPU 反弹缓冲区的字节大小。

  • 参数 8:到目前为止通过反弹缓冲区传输的总字节大小。

  • 参数 9:此事务中的待处理 IO 计数

cufio-internal-read-bb

此跟踪点跟踪通过内部 GPU 反弹缓冲区的 IO 读取,并且特定于 EXAScaler 文件系统和基于块设备的文件系统。此跟踪点位于每个 IO 的热 IO 路径跟踪中,并接受以下参数

  • 参数 1:应用程序 GPU(GPU ID)

  • 参数 2:GPU 反弹缓冲区(GPU ID)

  • 参数 3:文件描述符

  • 参数 4:文件偏移量

  • 参数 5:读取大小

  • 参数 6:应用程序 GPU 缓冲区偏移量

  • 参数 7:从 GPU 反弹缓冲区传输到应用程序 GPU 缓冲区的字节大小。

  • 参数 8:到目前为止通过反弹缓冲区传输的总字节大小。

  • 参数 9:此事务中的待处理 IO 计数。

cufio-internal-bb-done

此跟踪点跟踪通过反弹缓冲区的所有 IO,并在通过反弹缓冲区完成 IO 时调用。此跟踪点可用于跟踪通过反弹缓冲区的所有 IO,并接受以下参数

  • 参数 1:IO 类型 读取 - 0,写入 - 1

  • 参数 2:应用程序 GPU(GPU ID)

  • 参数 3:GPU 反弹缓冲区(GPU ID)

  • 参数 4:文件描述符

  • 参数 5:文件偏移量

  • 参数 6:读取/写入大小

  • 参数 7:GPU 缓冲区偏移量

  • 参数 8:IO 是否未对齐(1 - True,0 - False)

  • 参数 9:缓冲区是否已注册(1 - True,0 - False)

cufio-internal-io-done

此跟踪点跟踪通过 GDS 内核驱动程序的所有 IO。当 IO 完成时调用此跟踪点,并接受以下参数

  • 参数 1:IO 类型 读取 - 0,写入 - 1

  • 参数 2:执行 IO 的 GPU ID

  • 参数 3:文件描述符

  • 参数 4:文件偏移量

  • 参数 5:传输的总字节数

cufio-internal-map

此跟踪点跟踪使用 cuFileBufRegister 的 GPU 缓冲区注册,并接受以下参数

  • 参数 1:GPU ID

  • 参数 2:执行注册的 GPU 缓冲区大小

  • 参数 3:用于此缓冲区的 max_direct_io_size。

    阴影内存大小在 /etc/cufile.json 文件中设置。

  • 参数 4:布尔值,指示缓冲区是否已固定。

  • 参数 5:布尔值,指示此缓冲区是否为 GPU 反弹缓冲区。

  • 参数 6:GPU 偏移量。

可以通过运行以下命令找到这些跟踪点中每个参数的数据类型

# ./tplist -l /usr/local/cuda-x.y/lib/libcufile.so -vvv | grep cufio_px_read -A 7
cufio:cufio_px_read [sema 0x0]

以下是输出

# ./tplist -l /usr/local/cuda-x.y/lib/libcufile.so -vvv | grep cufio_px_read -A 7
cufio:cufio_px_read [sema 0x0]
  location #1 /usr/local/cuda-x.y/lib/libcufile.so 0x16437c
    argument #1 4 signed   bytes @ dx
    argument #2 8 signed   bytes @ cx
    argument #3 8 unsigned bytes @ si
    argument #4 8 signed   bytes @ di
    argument #5 8 signed   bytes @ r8
    argument #6 4 signed   bytes @ ax

18.2. 示例:跟踪发出 cuFileRead/ cuFileWrite 的进程的 IO 活动#

此示例提供了有关如何跟踪发出 cuFileReadcuFileWrite API 的进程的 IO 活动的信息。

  1. 运行以下命令。

    # ./funccount u:/usr/local/cuda-x.y/lib/libcufile.so:cufio_* -i 1 -T -p 59467
    Tracing 7 functions for "u:/usr/local/cuda-x.y/lib/libcufile.so:cufio_*"... Hit Ctrl-C to end.
    
  2. 查看输出,例如

    cufio_gds_write                          1891
    
    16:21:13
    FUNC                                    COUNT
    cufio_gds_write                          1852
    
    16:21:14
    FUNC                                    COUNT
    cufio_gds_write                          1865
    ^C
    16:21:14
    FUNC                                    COUNT
    cufio_gds_write                          1138
    Detaching...
    

18.3. 示例:显示通过 GDS 的所有 IO 的 IO 模式#

此示例提供了有关如何显示和理解通过 GDS 的所有 IO 的 IO 模式的信息。

  1. 运行以下命令

    # ./argdist -C 'u:/usr/local/cuda-x.y/lib/libcufile.so:cufio_gds_read():size_t:arg3# Size Distribution'
    
  2. 查看输出,例如

    [16:38:22]
    IO Size Distribution
        COUNT      EVENT
        4654       arg3 = 1048576
        7480       arg3 = 131072
        9029       arg3 = 65536
        13561      arg3 = 8192
        14200      arg3 = 4096
    [16:38:23]
    IO Size Distribution
        COUNT      EVENT
        4682       arg3 = 1048576
        7459       arg3 = 131072
        9049       arg3 = 65536
        13556      arg3 = 8192
        14085      arg3 = 4096
    [16:38:24]
    IO Size Distribution
        COUNT      EVENT
        4678       arg3 = 1048576
        7416       arg3 = 131072
        9018       arg3 = 65536
        13536      arg3 = 8192
        14082      arg3 = 4096
    

1M、128K、64K、8K 和 4K IO 都在通过 GDS 完成读取。

18.4. 了解进程的 IO 模式#

您可以查看输出以了解进程的 IO 模式。

  1. 运行以下命令。

    # ./argdist -C 'u:/usr/local/cuda-x.y/lib/libcufile.so:cufio_gds_read():size_t:arg3#IO
    Size Distribution' -p 59702
    
  2. 查看输出。

    [16:40:46]
    IO Size Distribution
        COUNT      EVENT
        20774      arg3 = 4096
    [16:40:47]
    IO Size Distribution
        COUNT      EVENT
        20727      arg3 = 4096
    [16:40:48]
    IO Size Distribution
        COUNT      EVENT
        20713      arg3 = 4096
    

进程 59702 发出 4K IO。

18.5. 不同 GPU 上具有文件描述符的进程的 IO 模式#

  1. 运行以下命令。

    # ./argdist -C
    'u:/usr/local/cuda-x.y/lib/libcufile.so:cufio_gds_read():int,int,size:arg1,
    arg6,arg3#IO Size Distribution arg1=fd, arg6=GPU# arg3=IOSize' -p `pgrep -n gdsio`
    
  2. 查看输出,例如

    [17:00:03]
    u:/usr/local/cuda-x.y/lib/libcufile.so:cufio_gds_read():int,int,size_t:arg1,arg6,arg3#IO Size Distribution arg1=fd, arg6=GPU# arg3=IOSize
        COUNT      EVENT
        5482       arg1 = 87, arg6 = 2, arg3 = 131072
        7361       arg1 = 88, arg6 = 1, arg3 = 65536
        9797       arg1 = 89, arg6 = 0, arg3 = 8192
        11145      arg1 = 74, arg6 = 3, arg3 = 4096
    [17:00:04]
    u:/usr/local/cuda-x.y/lib/libcufile.so:cufio_gds_read():int,int,size_t:arg1,arg6,arg3#IO Size Distribution arg1=fd, arg6=GPU# arg3=IOSize
        COUNT      EVENT
        5471       arg1 = 87, arg6 = 2, arg3 = 131072
        7409       arg1 = 88, arg6 = 1, arg3 = 65536
        9862       arg1 = 89, arg6 = 0, arg3 = 8192
        11079      arg1 = 74, arg6 = 3, arg3 = 4096
    [17:00:05]
    u:/usr/local/cuda-x.y/lib/libcufile.so:cufio_gds_read():int,int,size_t:arg1,arg6,arg3#IO Size Distribution arg1=fd, arg6=GPU# arg3=IOSize
        COUNT      EVENT
        5490       arg1 = 87, arg6 = 2, arg3 = 131072
        7402       arg1 = 88, arg6 = 1, arg3 = 65536
        9827       arg1 = 89, arg6 = 0, arg3 = 8192
        11131      arg1 = 74, arg6 = 3, arg3 = 4096
    

gdsio 向 GPU 2、1、0 和 3 的 4 个文件发出 READS,fd=87、88、89、74,IO-SIZE 分别为 128K、64K、8K 和 4K。

18.6. 确定 GPU 中进程的 IOPS 和带宽#

您可以确定 GPU 中每个进程的 IOPS 和带宽。

  1. 运行以下命令。

    #./argdist -C
    'u:/usr/local/cuda-x.y/lib/libcufile.so:cufio_gds_read():int,int,size_t:arg1,
    arg6,arg3:arg6==0||arg6==3#IO Size Distribution arg1=fd, arg6=GPU#
    arg3=IOSize' -p `pgrep -n gdsio`
    
  2. 查看输出。

    [17:49:33]
    u:/usr/local/cuda-x.y/lib/libcufile.so:cufio_gds_read():int,int,size_t:arg1,arg6,arg3:arg6==0||arg6==3#IO Size Distribution arg1=fd, arg6=GPU# arg3=IOSize
        COUNT      EVENT
        9826       arg1 = 89, arg6 = 0, arg3 = 8192
        11168      arg1 = 86, arg6 = 3, arg3 = 4096
    [17:49:34]
    u:/usr/local/cuda-x.y/lib/libcufile.so:cufio_gds_read():int,int,size_t:arg1,arg6,arg3:arg6==0||arg6==3#IO Size Distribution arg1=fd, arg6=GPU# arg3=IOSize
        COUNT      EVENT
        9815       arg1 = 89, arg6 = 0, arg3 = 8192
        11141      arg1 = 86, arg6 = 3, arg3 = 4096
    [17:49:35]
    u:/usr/local/cuda-x.y/lib/libcufile.so:cufio_gds_read():int,int,size_t:arg1,arg6,arg3:arg6==0||arg6==3#IO Size Distribution arg1=fd, arg6=GPU# arg3=IOSize
        COUNT      EVENT
        9914       arg1 = 89, arg6 = 0, arg3 = 8192
        11194      arg1 = 86, arg6 = 3, arg3 = 4096
    
  • gdsio 正在所有 4 个 GPU 上执行 IO,并且输出已针对 GPU 0 和 GPU 3 进行过滤。

  • 每个 GPU 的带宽为 GPU 0 - 9826 IOPS,块大小为 8K,带宽 = ~80MB/s 。

18.7. 显示发出 cuFileRead 的进程的读取频率#

您可以显示有关发出 cuFileRead API 的进程的读取频率的信息。

  1. 运行以下命令。

    #./argdist -C 'r:/usr/local/cuda-x.y/lib/libcufile.so:cuFileRead():u32:$PID'
    
  2. 查看输出,例如

    [17:58:01]
    r:/usr/local/cuda-x.y/lib/libcufile.so:cuFileRead():u32:$PID
        COUNT      EVENT
        31191      $PID = 60492
        31281      $PID = 60593
    [17:58:02]
    r:/usr/local/cuda-x.y/lib/libcufile.so:cuFileRead():u32:$PID
        COUNT      EVENT
        11741      $PID = 60669
        30447      $PID = 60593
        30670      $PID = 60492
    [17:58:03]
    r:/usr/local/cuda-x.y/lib/libcufile.so:cuFileRead():u32:$PID
        COUNT      EVENT
        29887      $PID = 60593
        29974      $PID = 60669
        30017      $PID = 60492
    [17:58:04]
    r:/usr/local/cuda-x.y/lib/libcufile.so:cuFileRead():u32:$PID
        COUNT      EVENT
        29972      $PID = 60593
        30062      $PID = 60492
        30068      $PID = 60669
    

18.8. 显示 cuFileRead 花费超过 0.1 毫秒时的读取频率#

您可以显示 cuFileRead API 花费超过 0.1 毫秒时的读取频率。

  1. 运行以下命令。

    #./argdist -C 'r:/usr/local/cuda-x.y/lib/libcufile.so:cuFileRead():u32:$PID:$latency > 100000'
    
  2. 查看输出,例如

    [18:07:35]
    r:/usr/local/cuda-x.y/lib/libcufile.so:cuFileRead():u32:$PID:$latency > 100000
        COUNT      EVENT
        17755      $PID = 60772
    [18:07:36]
    r:/usr/local/cuda-x.y/lib/libcufile.so:cuFileRead():u32:$PID:$latency > 100000
        COUNT      EVENT
        17884      $PID = 60772
    [18:07:37]
    r:/usr/local/cuda-x.y/lib/libcufile.so:cuFileRead():u32:$PID:$latency > 100000
        COUNT      EVENT
        17748      $PID = 60772
    [18:07:38]
    r:/usr/local/cuda-x.y/lib/libcufile.so:cuFileRead():u32:$PID:$latency > 100000
        COUNT      EVENT
        17898      $PID = 60772
    [18:07:39]
    r:/usr/local/cuda-x.y/lib/libcufile.so:cuFileRead():u32:$PID:$latency > 100000
        COUNT      EVENT
        17811      $PID = 60772
    

18.9. 显示每个进程的 cuFileRead 延迟#

您可以显示每个进程的 cuFileRead API 的延迟。

  1. 运行以下命令。

    #./funclatency /usr/local/cuda-x.y/lib/libcufile.so:cuFileRead -i 1 -T -u
    
  2. 查看输出,例如

    Tracing 1 functions for
    "/usr/local/cuda-x.y/lib/libcufile.so:cuFileRead"... Hit Ctrl-C to end.
    

    以下是两个进程,PID 为 60999 和 PID 为 60894,它们正在发出 cuFileRead

    18:12:11
    Function = cuFileRead [60999]
         usecs               : count     distribution
             0 -> 1          : 0        |                                        |
             2 -> 3          : 0        |                                        |
             4 -> 7          : 0        |                                        |
             8 -> 15         : 0        |                                        |
            16 -> 31         : 0        |                                        |
            32 -> 63         : 0        |                                        |
            64 -> 127        : 17973    |****************************************|
           128 -> 255        : 13383    |*****************************           |
           256 -> 511        : 27       |                                        |
    Function = cuFileRead [60894]
         usecs               : count     distribution
             0 -> 1          : 0        |                                        |
             2 -> 3          : 0        |                                        |
             4 -> 7          : 0        |                                        |
             8 -> 15         : 0        |                                        |
            16 -> 31         : 0        |                                        |
            32 -> 63         : 0        |                                        |
            64 -> 127        : 17990    |****************************************|
           128 -> 255        : 13329    |*****************************           |
           256 -> 511        : 19       |                                        |
    
    18:12:12
    Function = cuFileRead [60999]
         usecs               : count     distribution
             0 -> 1          : 0        |                                        |
             2 -> 3          : 0        |                                        |
             4 -> 7          : 0        |                                        |
             8 -> 15         : 0        |                                        |
            16 -> 31         : 0        |                                        |
            32 -> 63         : 0        |                                        |
            64 -> 127        : 18209    |****************************************|
           128 -> 255        : 13047    |****************************            |
           256 -> 511        : 58       |                                        |
    
    Function = cuFileRead [60894]
         usecs               : count     distribution
             0 -> 1          : 0        |                                        |
             2 -> 3          : 0        |                                        |
             4 -> 7          : 0        |                                        |
             8 -> 15         : 0        |                                        |
            16 -> 31         : 0        |                                        |
            32 -> 63         : 0        |                                        |
            64 -> 127        : 18199    |****************************************|
           128 -> 255        : 13015    |****************************            |
           256 -> 511        : 46       |                                        |
           512 -> 1023       : 1        |
    

18.10. 示例:跟踪发出 cuFileBufRegister 的进程#

此示例显示您可以跟踪发出 cuFileBufRegister API 的进程。

  1. 运行以下命令

    # ./trace 'u:/usr/local/cuda-x.y/lib/libcufile.so:cufio-internal-map "GPU
    %d Size %d Bounce-Buffer %d",arg1,arg2,arg5'
    
  2. 查看输出,例如

    PID     TID     COMM     FUNC             -
    62624   62624   gdsio_verify    cufio-internal-map GPU 0 Size 1048576 Bounce-Buffer 1
    62659   62726   fio             cufio-internal-map GPU 0 Size 8192 Bounce-Buffer 0
    62659   62728   fio             cufio-internal-map GPU 2 Size 131072 Bounce-Buffer 0
    62659   62727   fio             cufio-internal-map GPU 1 Size 65536 Bounce-Buffer 0
    62659   62725   fio             cufio-internal-map GPU 3 Size 4096 Bounce-Buffer 0
    

gdsio_verify 发出了 IO,但它未使用 cuFileBufRegister 注册 GPU 内存。因此,GDS 库在 GPU 0 上固定了 1M 的反弹缓冲区。另一方面,FIO 在 GPU 2 上发出了 128K 的 cuFileBufRegister

18.11. 示例:跟踪进程在调用 cuFileBufRegister 时是否恒定#

您可以跟踪进程在调用 cuFileBufRegister API 时是否恒定。

  1. 运行以下命令

    # ./trace 'u:/usr/local/cuda-x.y/lib/libcufile.so:cufio-internal-map (arg5 == 0)
    "GPU %d Size %d",arg1,arg2'
    
  2. 查看输出,例如

    PID     TID     COMM            FUNC             -
    444     472     cufile_sample_0 cufio-internal-map GPU 0 Size 1048576
    444     472     cufile_sample_0 cufio-internal-map GPU 0 Size 1048576
    444     472     cufile_sample_0 cufio-internal-map GPU 0 Size 1048576
    444     472     cufile_sample_0 cufio-internal-map GPU 0 Size 1048576
    444     472     cufile_sample_0 cufio-internal-map GPU 0 Size 1048576
    444     472     cufile_sample_0 cufio-internal-map GPU 0 Size 1048576
    444     472     cufile_sample_0 cufio-internal-map GPU 0 Size 1048576
    444     472     cufile_sample_0 cufio-internal-map GPU 0 Size 1048576
    444     472     cufile_sample_0 cufio-internal-map GPU 0 Size 1048576
    444     472     cufile_sample_0 cufio-internal-map GPU 0 Size 1048576
    444     472     cufile_sample_0 cufio-internal-map GPU 0 Size 1048576
    444     472     cufile_sample_0 cufio-internal-map GPU 0 Size 1048576
    444     472     cufile_sample_0 cufio-internal-map GPU 0 Size 1048576
    444     472     cufile_sample_0 cufio-internal-map GPU 0 Size 1048576
    444     472     cufile_sample_0 cufio-internal-map GPU 0 Size 1048576
    

如本示例所示,进程中有一个线程在 GPU 0 上持续发出 1M 的 cuFileBufRegister。这可能意味着 API 在循环中被调用,并且可能会影响性能。

注意

cuFileBufRegister 涉及固定 GPU 内存,这是一项昂贵的操作。

18.12. 示例:监视正在通过反弹缓冲区的 IO#

此示例显示了如何监视 IO 是否正在通过反弹缓冲区。

  1. 运行以下命令

    # ./trace 'u:/usr/local/cuda-x.y/lib/libcufile.so:cufio-internal-bb-done
    "Application GPU %d Bounce-Buffer GPU %d Transfer Size %d Unaligned %d Registered %d",
    arg2,arg3,arg8,arg9,arg10'
    
  2. 查看输出,例如

PID TID COMM  FUNC             -
1013 1041  gdsio App-GPU 0 Bounce-Buffer GPU 0 Transfer Size 1048576 Unaligned 1 Registered 0
1013 1042  gdsio App-GPU 3 Bounce-Buffer GPU 3 Transfer Size 1048576 Unaligned 1 Registered 0
1013 1041  gdsio App-GPU 0 Bounce-Buffer GPU 0 Transfer Size 1048576 Unaligned 1 Registered 0
1013 1042  gdsio App-GPU 3 Bounce-Buffer GPU 3 Transfer Size 1048576 Unaligned 1 Registered 0

The ``gdsio`` app has 2 threads and both are doing unaligned IO on GPU 0 and GPU 3. Since the IO is unaligned, bounce buffers are also from the same application GPU.

18.13. 示例:跟踪 cuFileRead 和 cuFileWrite 失败、打印、错误代码和失败时间#

此示例显示了如何跟踪 cuFileReadcuFileWrite 失败、打印、错误代码和失败时间。

  1. 运行以下命令

    # ./trace 'r:/usr/local/cuda-x.y/lib/libcufile.so:cuFileRead ((int)retval < 0)
    "cuFileRead failed: %d", retval' 'r:/usr/local/cuda-x.y/lib/libcufile.so:cuFileWrite ((int)retval < 0)
    "cuFileWrite failed: %d", retval' -T
    
  2. 查看输出,例如

    TIME      PID      TID               COMM                     FUNC             -
    23:22:16 4201    4229    gdsio           cuFileRead       cuFileRead failed: -5
    23:22:42 4237    4265    gdsio           cuFileWrite      cuFileWrite failed: -5
    

在本示例中,观察到两个失败,返回代码为 EIO (-5),并带有时间戳。

18.14. 示例:每个 GDS 进程的用户空间统计信息#

cuFile 库以每个进程的 API 级别计数器的形式导出用户级别统计信息。除了常规 GDS IO 路径之外,还有用户空间文件系统和 IO 兼容模式的路径,这些模式使用 POSIX 读取/写入,这些读取/写入不通过 nvidia-fs 驱动程序。用户级别统计信息在这些场景中更有用。

计数器有一个详细级别,用户可以使用 JSON 配置文件指定该级别以启用和设置级别。以下描述了各种详细级别。

表 10 每个 GDS 进程的用户空间统计信息#

级别

描述

级别 0

cuFile 统计信息将被禁用。

级别 1

cuFile 统计信息将仅报告全局计数器,例如总体吞吐量、平均延迟和错误计数。

级别 2

除了全局计数器之外,还将报告 IO 大小直方图,以提供有关访问模式的信息。

级别 3

在此级别,将报告每个 GPU 的计数器以及 cuFile 内部池缓冲区的实时使用情况。

以下是使用 /etc/cufile.json 文件启用 GDS 统计信息的 JSON 配置键

"profile": {
                // cufile stats level(0-3)
                "cufile_stats": 3
            },

18.15. 示例:查看进程的 GDS 用户级别统计信息#

此示例显示了如何使用 gds_stats 工具显示进程的用户级别统计信息。

先决条件:在运行该工具之前,请确保 IO 应用程序处于活动状态,并且 gds_stats 具有与应用程序相同的用户权限。

gds_stats 工具可用于读取由 libcufile.so 导出的统计信息。

统计信息的输出显示在标准输出中。如果用户权限不同,则可能没有足够的权限来查看统计信息。gds_stats 的未来版本将把 nvidia-fs 内核级别统计信息集成到此工具中。

要使用该工具,请运行以下命令

$ /usr/local/cuda-x.y/tools/gds_stats -p <pidof application> -l <stats_level(1-3)>

在指定统计信息级别时,请确保在 /etc/cufile.json 文件中也启用了相应的级别 (profile.cufile_stats)。

GDS 用户级别统计信息在库关闭或运行 cuFileDriverClose API 时记录到 cufile.log 文件一次。要查看日志文件中的统计信息,请将日志级别设置为 INFO。

18.16. 示例:显示每个 GDS 进程的示例用户级别统计信息#

此示例显示了如何显示每个 GDS 进程的示例用户级别统计信息。

  1. 运行以下命令

    $ ./gds_stats -p 23198 -l 3
    
  2. 查看输出,例如

    cuFile STATS VERSION : 8
    GLOBAL STATS:
    Read: ok = 215814 err = 0
    Write: ok = 0 err = 0
    HandleRegister: ok = 1 err = 0
    HandleDeregister: ok = 0 err = 0
    BufRegister: ok = 128 err = 0
    BufDeregister: ok = 0 err = 0
    BatchSubmit: ok = 0 err = 0
    BatchComplete: ok = 0 err = 0
    BatchSetup: ok = 0 err = 0
    BatchCancel: ok = 0 err = 0
    BatchDestroy: ok = 0 err = 0
    BatchEnqueued: ok = 0 err = 0
    PosixBatchEnqueued: ok = 0 err = 0
    BatchProcessed: ok = 0 err = 0
    PosixBatchProcessed: ok = 0 err = 0
    Total Read Size (MiB): 107907
    Read BandWidth (GiB/s): 2.50343
    Avg Read Latency (us): 49731
    Total Write Size (MiB): 0
    Write BandWidth (GiB/s): 0
    Avg Write Latency (us): 0
    Total Batch Read Size (MiB): 0
    Total Batch Write Size (MiB): 0
    Batch Read BandWidth (GiB/s): 0
    Batch Write BandWidth (GiB/s): 0
    Avg Batch Submit Latency (us): 0
    Avg Batch Completion Latency (us): 0
    READ-WRITE SIZE HISTOGRAM :
    0-4(KiB): 0  0
    4-8(KiB): 0  0
    8-16(KiB): 0  0
    16-32(KiB): 0  0
    32-64(KiB): 0  0
    64-128(KiB): 0  0
    128-256(KiB): 0  0
    256-512(KiB): 0  0
    512-1024(KiB): 0  0
    1024-2048(KiB): 107907  0
    2048-4096(KiB): 0  0
    4096-8192(KiB): 0  0
    8192-16384(KiB): 0  0
    16384-32768(KiB): 0  0
    32768-65536(KiB): 0  0
    65536-...(KiB): 0  0
    PER_GPU STATS:
    GPU 0(UUID: ce4dfa044611339ca1e22bf10a772fe) Read: bw=2.50531 util(%)=12791 n=107907 posix=0 unalign=0 dr=0 r_sparse=0 r_inline=0 err=0 MiB=107907 Write: bw=0 util(%)=0 n=0 posix=0 unalign=0 dr=0 err=0 MiB=0 BufRegister: n=128 err=0 free=0 MiB=128
    PER_GPU POOL BUFFER STATS:
    PER_GPU POSIX POOL BUFFER STATS:
    PER_GPU RDMA STATS:
    GPU 0000:43:00.0(UUID: ce4dfa044611339ca1e22bf10a772fe) :
    
    RDMA MRSTATS:
    peer name   nr_mrs      mr_size(MiB)
    mlx5_0      1           2
    mlx5_1      1           2
    
    PER GPU THREAD POOL STATS:
    gpu node: 0 enqueues:0 completes:0 pending suspends:0 pending yields:0 active:0 suspends:0
    

19. GPUDirect Storage 中的用户空间计数器#

下表提供了有关 GDS 中用户空间计数器的信息。

表 11 全局 cuFile 计数器#

计数器名称

描述

文件总数

使用 cuFileHandleRegister 成功注册的文件总数。这是一个累积计数器。

cuFileHandleDeregister 不会更改此计数器。

读取错误总数

cuFileRead 错误的​​总数。

读取大小总计

使用 cuFileRead 读取的总字节数(MB)。

读取带宽

一秒时间段内的平均总体读取吞吐量(GiB/s)。

平均读取延迟

一秒时间段内的总体平均读取延迟(微秒)。

写入错误总数

cuFileWrite 错误的​​总数。

写入大小总计

使用 cuFileWrite 写入的总字节数(MB)。

写入带宽

一秒时间段内的平均总体写入吞吐量(GiB/s)。

平均写入延迟

一秒时间段内的总体平均读取延迟(微秒)。

批量读取大小总计

使用 cuFile 批量模式读取的总字节数(MB)。

批量写入大小总计

使用 cuFile 批量模式写入的总字节数(MB)。

批量读取带宽

cuFile 批量模式在一秒时间段内的平均总体读取吞吐量(GiB/s)。

批量写入带宽

cuFile 批量模式在一秒时间段内的平均总体写入吞吐量(GiB/s)。

平均批量提交延迟

使用 cuFileBatchIOSubmit 在一秒时间段内的总体平均 cuFile 批量 IO 提交延迟(微秒)。

平均批量完成延迟

一秒时间段内的总体平均 cuFile 批量 IO 完成延迟(微秒)。这包括提交和完成时间。

表 12 IO 大小直方图#

计数器名称

描述

Read

基于 IO 大小的 cuFileRead 请求数量分布。Bin Size 使用 4K 对数刻度。

Write

基于 IO 大小的 cuFileWrite 请求数量分布。Bin Size 使用 4K 对数刻度。

表 13 每个 GPU 的计数器#

计数器名称

描述

Read.bw/Write.bw

每个 GPU 的平均 GPU 读取/写入带宽(GiB/s)。

Read.util/Write.util

每个 GPU 的平均读取/写入利用率(%)。如果 A 是资源在时间间隔 T 内处于繁忙状态的总时长,则利用率定义为 A/T。此处报告的利用率超过一秒时间段。

Read.n/Write.n

每个 GPU 的 cuFileRead/cuFileWrite 请求数。

Read.posix/Write.posix

每个 GPU 使用 POSIX 读取/写入 API 的 cuFileRead/cuFileWrite 数量。

Read.dr/Write.dr

已使用动态路由为 GPU 发出的 cuFileRead/cuFileWrites 的数量。

如果路由策略使用 SYS_MEM,则除了 dr 计数器之外,GPU posix 读取/写入计数器也会递增。注意:此计数器不指示实际用于路由 IO 的 GPU。对于后一种信息,需要观察 PER_GPU POOL BUFFER STATS/PER_GPU POSIX POOL BUFFER STATS

Read.unalign/Write.unalign

每个 GPU 的 cuFileRead/cuFileWrite 数量,其中至少有一个 IO 参数未 4K 对齐。这可以是大小、文件偏移量或设备指针。

Read.error/Write.error

每个 GPU 的 cuFileRead/cuFileWrite 错误数。

Read.mb/Write.mb

每个 GPU 使用 cuFileRead/cuFileWrite 读取/写入的总字节数(MB)。

BufRegister.n

每个 GPU 的 cuFileBufRegister 调用总数。

BufRegister.err

使用 cuFileBufRegister 看到的每个 GPU 的错误总数。

BufRegister.free

每个 GPU 的 cuFileBufRegister 调用总数。

BufRegister.mb

每个 GPU 当前注册的总字节数(MB)。

表 14 每个 GPU 的反弹缓冲区计数器#

计数器名称

描述

pool_size_mb

为每个 GPU 反弹缓冲区分配的缓冲区总大小(MB)。

used_mb

当前每个 GPU 用于基于反弹缓冲区的 IO 的缓冲区总大小。

usage

当前使用的反弹缓冲区的比例。

表 15 注册调用#

计数器名称

描述

HandleRegister

HandleDeregister

ok:已发出并成功完成的 cuFileHandleRegister 调用数。

err:已发出并完成但出现错误的 cuFileHandleRegister 调用数。ok:已发出并成功完成的 cuFileHandleDeregister 调用数。

err:已发出并完成但出现错误的 cuFileHandleDeregister 调用数。

BufRegister

ok:已发出并成功完成的 cuFileBufRegister 调用数。

err:已发出并完成但出现错误的 cuFileBufRegister 调用数。

BufDeregister

ok:已发出并成功完成的 cuFileBufDeregister 调用数。

err:已发出并完成但出现错误的 cuFileBufDeregister 调用数。

BatchSubmit

ok:已发出并成功完成的 cuFileBatchIOSubmit 调用数。

err:已发出并完成但出现错误的 cuFileBatchIOSubmit 调用数。

BatchComplete

ok:已发出并成功完成的 cuFileBatchIOGetStatus 调用数。

err:已发出并完成但出现错误的 cuFileBatchIOGetStatus 调用数。

BatchSetup

ok:已发出并成功完成的 cuFileBatchIOSetUp 调用数。

err:已发出并完成但出现错误的 cuFileBatchIOSetUp 调用数。

BatchCancel

ok:已发出并成功完成的 cuFileBatchIOCancel 调用数。

err:已发出并完成但出现错误的 cuFileBatchIOCancel 调用数。

BatchDestroy

ok:已发出并成功完成的 cuFileBatchIODestroy 调用数。

err:已发出并完成但出现错误的 cuFileBatchIODestroy 调用数。

BatchEnqueued

对于具有未对齐大小/偏移量的批量条目,该条目可能具有对齐(GDS 路径)和未对齐(Posix 路径)部分。此条目指示在这种情况下 GDS 路径 IO 的数量。这些 IO 不会直接提交,而是排队到线程池中。

ok:成功排队到线程池的 GDS 路径 IO 数。

err:无法排队到线程池的 GDS 路径 IO 数。

PosixBatchEnqueued

与 BatchEnqueued 类似,但用于排队的 Posix IO 数。

ok:成功排队到线程池的 Posix 路径 IO 数。

err:无法排队到线程池的 Posix 路径 IO 数。

BatchProcessed

此计数器指示使用 BatchEnqueued 跟踪的 IO 的已处理 IO 数。

ok:成功处理的 IO 数。

err:完成但出现错误的 IO 数。

PosixBatchProcessed

此计数器指示使用 PosixBatchEnqueued 跟踪的 IO 的已处理 IO 数。

ok:成功处理的 IO 数。

err:完成但出现错误的 IO 数。

19.1. 每个 GPU 中 IO 使用率的分布#

cuFile 库具有每个应用程序 GPU 的 IO 利用率指标。此指标指示 cuFile 资源在 IO 中繁忙的时间量(以百分比表示)。

要运行单线程 gdsio 测试,请运行以下命令

$./gdsio -f /mnt/md1/test -d 0 -n 0 -w 1 -s 10G -i 4K -x 0 -I 1

以下是示例输出

PER_GPU STATS
GPU 0 Read: bw=0 util(%)=0 n=0 posix=0 unalign=0 err=0 mb=0 Write: bw=0.154598
util(%)=89 n=510588 posix=0 unalign=0 err=0 mb=1994 BufRegister: n=1 err=0 free=0 mb=0

util 指标表示应用程序在 89% 的时间内在 GPU 0 上完成 IO。

要使用两个线程运行 gdsio 测试,请运行以下命令

$./gdsio -f /mnt/md1/test -d 0 -n 0 -w 2 -s 10G -i 4K -x 0 -I 1

以下是示例输出

PER_GPU STATS
GPU 0 Read: bw=0 util(%)=0 n=0 posix=0 unalign=0 err=0 mb=0 Write: bw=0.164967 util(%)=186 n=140854 posix=0 unalign=0 err=0 mb=550 BufRegister: n=2 err=0 free=0 mb=0

现在利用率为 ~186%,这表明每个 GPU 用于 IO 的并行度。

19.2. 动态路由的用户空间统计信息#

gds_statsPER_GPU 部分有一个 dr 计数器,该计数器指示已使用动态路由为 GPU 发出了多少 cuFileRead/ cuFileWrite

$ ./gds_stats -p <pidof application> -l 3

    GPU 0 Read: bw=0 util(%)=0 n=0 posix=0 unalign=0 dr=0 r_sparse=0 r_inline=0
 err=0 MiB=0 Write: bw=3.37598 util(%)=532 n=6629 posix=0 unalign=0 dr=6629 err=0
 MiB=6629 BufRegister: n=4 err=0 free=0 MiB=4
    GPU 1 Read: bw=0 util(%)=0 n=0 posix=0 unalign=0 dr=0 r_sparse=0 r_inline=0
 err=0 MiB=0 Write: bw=3.29297 util(%)=523 n=6637 posix=0 unalign=0 dr=6637 err=0
 MiB=6637 BufRegister: n=4 err=0 free=0 MiB=4

20. GPUDirect Storage 中的用户空间 RDMA 计数器#

该库提供计数器来监视每个 GPU 级别的 RDMA 流量,并且要求 cuFile 以值为 3 的详细级别启动。

cuFile RDMA IO 计数器 (PER_GPU RDMA STATS) 提供了以下信息

  • 每列存储 GPU 和 NIC 之间发送/接收的总字节数。

  • 每行显示 RDMA 负载相对于所有 NIC 的 GPU 分布。

  • 每行反映了 GPU 与 NIC 的亲和性顺序。

    理想情况下,所有流量都应通过具有最佳亲和性或最靠近 GPU 的 NIC 路由,如 示例 1 中所示。

在表中每个 NIC 条目的注释中,主编号是以 GPU 和 NIC 之间的跳数表示的 pci 距离,次编号表示 NIC 的当前带宽(link_width 乘以 pci_generation)。GPU 用于 RDMA 的 NIC 从 rdma_dev_addr_list cufile.json 属性加载

"rdma_dev_addr_list": [
      "172.172.1.240",
      "172.172.1.241",
      "172.172.1.242",
      "172.172.1.243",
      "172.172.1.244",
      "172.172.1.245",
      "172.172.1.246",
      "172.172.1.247" ],

每个 IP 地址对应于一个 IB 设备,该设备在 RDMA 计数器表中显示为列条目。

20.1. cuFile RDMA IO 计数器 (PER_GPU RDMA STATS)#

下表列出了 cuFile RDMA IO 计数器。

表 16 cuFile RDMA IO 计数器 (PER_GPU RDMA STATS)#

条目

描述

GPU

总线设备功能

NIC

+)Bus device function
+)Device Attributes
   ++)pci-distance between GPU and NIC
   ++)device bandwidth indicator
+)Send/Receive bytes
表 17 示例 1#

GPU 0000:34:00.0

mlx5_3 (3:48):6293

mlx5_5 (7:48):0

mlx5_15 (138:48:0

mlx5_15 (138:48:0)

mlx5_17 (138:48):0

mlx5_9 (138:48):0

mlx5_13 (138:48):0

mlx5_7 (138:12):0

GPU 0000:36:00.0

mlx5_3 (3:48):6077

mlx5_5 (7:48):1858

mlx5_15 (138:48):0

mlx5_19 (138:48):0

mlx5_17 (138:48):0

mlx5_9 (138:48):0

mlx5_13 (138:48):0

mlx5_7 (138:12):0

GPU 0000:3b:00.0

mlx5_5 (3:48):5467

mlx5_3 (7:48):0

mlx5_15 (138:48):0

mlx5_19 (138:48):0

mlx5_17 (138:48):0

mlx5_9 (138:48):0

mlx5_13 (138:48):0

mlx5_7 (138:12):0

GPU 0000:57:00.0

mlx5_7 (3:12):4741

mlx5_9 (7:48):0

mlx5_15 (138:48):0

mlx5_19 (138:48):0

mlx5_5 (138:48):0

mlx5_17 (138:48):0

mlx5_13 (138:48):0

mlx5_3 (138:48):0

GPU 0000:59:00.0

mlx5_7 (3:12):4744

mlx5_9 (7:48):1473

mlx5_15 (138:48):0

mlx5_19 (138:48):0

mlx5_5 (138:48):0

mlx5_17 (138:48):0

mlx5_13 (138:48):0

mlx5_3 (138:48):0

GPU 0000:5c:00.0

mlx5_9 (3:48):4707

mlx5_7 (7:12):0

mlx5_15 (138:48):0

mlx5_19 (138:48):0

mlx5_5 (138:48):0

mlx5_17 (138:48):0

mlx5_13 (138:48):0

mlx5_3 (138:48):0

GPU 0000:5e:00.0

mlx5_9 (3:48):4700

mlx5_7 (7:12):0

mlx5_15 (138:48):0

mlx5_19 (138:48):0

mlx5_5 (138:48):0

mlx5_17 (138:48):0

mlx5_13 (138:48):0

mlx5_3 (138:48):0

20.2. cuFile RDMA 内存注册计数器 (RDMA MRSTATS)#

以下表格列出了 cuFile RDMA 内存注册计数器。

表 18 cuFile RDMA IO 计数器 (PER_GPU RDMA STATS)#

条目

描述

对等名称

网卡的系统名称。

nr_mrs

每个网卡的活动内存注册计数。

mr_size(mb)

总大小

表 19 示例 2#

对等名称

nr_ms

mr_size (mb)

mlx5_3

128

128

mlx5_5

128

128

mlx5_11

0

0

mlx5_1

0

0

mlx5_15

128

128

mlx5_19

128

128

mlx5_17

128

128

mlx5_9

128

128

mlx5_13

128

128

mlx5_7

128

128

21. 问题诊断速查表#

以下表格可以帮助用户诊断 GDS 问题。

请务必检查以下变量,并观察性能是否达到预期。

影响性能的变量

描述

启用/禁用功能的步骤(“操作方法”)

兼容模式

cufile.json 中禁用兼容模式

在 cufile.json 中设置 allow_compat_mode: false

将 CUFILE_FORCE_COMPAT_MODE 环境变量设置为 false。

日志级别

在 cufile.json 中将日志级别设置为 ERROR

以下 cufile.json 中的设置会将日志级别设置为 ERROR。

"logging": {
         // log

目录,如果未启用,将在当前工作目录下创建日志文件

//"dir": "/home/<xxxx>",
        // NOTICE|ERROR|WARN|INFO|DEBUG|TRACE (in decreasing order of severity)
       "level": "ERROR"
        },

Nvidia-fs 统计信息

确保 nvidia-fs 读取/写入统计信息已禁用。这些统计信息可能会对小 IO 大小产生性能影响。默认情况下,这些信息是禁用的。

要检查统计信息的当前状态,请使用以下命令。

#cat /sys/module/nvidia_fs/parameters/rw_stats_enabled

0 - 禁用

1 - 启用

要禁用它们,

echo 0 > /sys/module/nvidia_fs/parameters/rw_stats_enabled

GDR 统计信息/RDMA 统计信息(CQE 错误)

放宽排序

对于分布式文件系统,请确保网卡已启用放宽排序

在 CX-6 上设置“MAX_ACC_OUT_READ=44”。

对于 CX-7,设置“MAX_ACC_OUT_READ=128”。

sudo mlxconfig -y -d <NIC> set ADVANCED_PCI_SETTINGS=1

sudo mlxconfig -y -d <NIC> set MAX_ACC_OUT_READ=44|128

sudo reboot

持久模式

启用持久模式

时钟速度

将时钟速度设置为最大值

BAR 大小

确保 BAR 大小已启用为最大可能值

Numa 亲缘性

在 NIC-GPU 位于同一交换机中的进程中设置 numa 亲缘性

MRRS

为 NIC/NVMe 设置 PCIe 最大读取请求大小。指定最大读取请求大小使请求者 (NIC/NVME) 能够从 GPU 内存读取数据,大小可达指定大小,以提高从 GPU 到存储的写入性能。

使用以下命令检查设置

# lspci -vvv -s <B:D.F> | grep -i MaxReadReq

读取当前值

#setpci -v -s <B:D.F> cap_exp+8.w

设置为 4K

#setpci -v -s <B:D.F> cap_exp+8.w= ``5`` 000:7000

设置为 512 字节

#setpci -v -s <B:D.F> cap_exp+8.w= ``2`` 000:7000

可接受的值为:0 - 128B,1 - 256B,2 - 512B,3 - 1024B,4 - 2048B 和 5 - 4096B。

警告:指定此范围之外的选择器索引可能会导致系统崩溃。

对于 ROCE 设置,请考虑以下附加项

CPU 调速器

性能

#cpupower frequency-set -g performance

RX/TX 环

将它们设置为最大值

#ethtool -G $adapter rx $(ethtool -g $adapter | awk '/RX:/ {print $NF; exit}')#ethtool -G $adapter tx $(ethtool -g $adapter | awk '/TX:/ {print $NF; exit}')

RX/TX 通道

设置为允许的最大值

#ethtool -L $adapter combined 15

LRO

开启大接收卸载

#ethtool -K $adapter lro on

IRQ 亲缘性

将 IRQ 亲缘性设置为仿射 NUMA 节点

IRQ 平衡

关闭 IRQ 平衡器

#systemctl stop irqbalance

TX 队列长度

增加 TX 队列长度

#ifconfig $adapter $addr/$netmask mtu 9000 txqueuelen 20000 up

如果以上步骤没有帮助,请收集以下信息并与我们分享。

测量 GDR 性能

对于 RDMA 连接和性能问题,请运行 ib_read 和 ib_write 测试,并启用 cuda 和 GPU

请按照 linux-rdma/perftest 的说明进行操作

在测试中使用选项

--use_cuda=<gpu index>

使用 Nsight Systems

对于 RDMA 连接和性能问题,请运行 ib_read 和 ib_write 测试,并启用 cuda 和 GPU

cat /etc/cufile.json | grep nvtx

// nvtx profiling on/off

"nvtx": true,

/usr/local/cuda/bin/nsys profile <command>

描述环境

虚拟化(Docker 或实际 VM)或 BM

# printenv

# lsb_release -a

# dmidecode

# docker info

# docker container inspect <container id>

收集 gds 日志

收集 cufile.log

/usr/local/cuda/gds/tools/gds_log_collection.py

# /usr/local/cuda/gds/tools/gds_log_collection.py

调试

Dmesg 错误?

检查内核错误

# dmesg

# /var/log/kern.log

MiG 模式已启用?

检查是否启用 MIG

# nvidia-smi mig -lgi

FM 已启用或未启用

对于基于 NVSwitch 的系统。检查 fabric manager 是否正在运行且处于活动状态,并且没有任何错误

# systemctl status nvidia fabricmanager