简介

NVSHMEM 是一个软件库,为 NVIDIA ® GPU 集群实现了 OpenSHMEM 应用程序编程接口 (API)。OpenSHMEM 是一个社区标准、单边通信 API,提供分区全局地址空间 (PGAS) 并行编程模型。OpenSHMEM 规范以及 NVSHMEM 的一个关键目标是提供一个易于使用的接口,同时提供高性能和最小的软件开销。

OpenSHMEM 规范正在积极开发中,定期发布版本,扩展其功能集并扩展其使用新兴节点和集群架构的能力。当前版本的 NVSHMEM 基于 OpenSHMEM 1.3 版本 API,并且还包含来自 OpenSHMEM 较新版本的许多功能。尽管 NVSHMEM 基于 OpenSHMEM,但仍存在重要的差异,本指南将详细介绍这些差异。

NVSHMEM 提供了一个易于使用的主机端接口,用于分配对称内存,该内存可以分布在通过 NVLink、PCIe 和 InfiniBand 互连的 NVIDIA GPU 集群中。设备端 API 可以由 CUDA 内核线程调用,以通过单边读取(get)、写入(put)和原子更新 API 调用有效地访问对称内存中的位置。此外,可以直接被 GPU 访问的对称内存,例如,位于本地 GPU 或通过 NVLink 连接的对等 GPU 上的内存区域,可以被查询并通过 NVSHMEM 库提供的指针直接访问。

主要特性

NVSHMEM 扩展了 OpenSHMEM API 以支持 NVIDIA GPU 集群。以下提供了一些关键扩展的信息

  • 支持对称分配 GPU 内存。
  • 支持 GPU 发起的通信,包括对 CUDA 类型的支持。
  • 一个新的 API 调用,用于跨一组 GPU 集合启动 CUDA 内核。
  • 基于流的 API,允许将从 CPU 发起的数据移动操作卸载到 GPU,并根据 CUDA 流进行排序。
  • 线程组通信,其中 CUDA 内核中来自整个 warp 或线程块的线程可以集体参与通信操作。
  • 区分同步和非同步操作,以利用 GPU 内存模型中操作的优势(弱或强)。

以下是 NVSHMEM 和 OpenSHMEM 之间差异的摘要。

  • API 名称以 “nv” 为前缀,以便能够将 NVSHMEM 与现有的 OpenSHMEM 库混合使用。
  • NVSHMEM 通信例程的所有缓冲区参数都必须是对称的。
  • NVSHMEM 为阻塞操作返回的数据提供弱排序,这些操作获取数据。可以通过 nvshmem_fence 操作强制排序。

有关 OpenSHMEM 规范的更多信息,请参阅 openshmem.org

通信传输

除了本地 GPU-GPU 通信外,NVSHMEM 还通过两个额外的通道支持单边网络通信

  1. InfiniBand 或 RoCE over verbs 接口
  2. InfiniBand 或 RoCE 使用 UCX(实验性)。

这些传输的编译和使用可以通过环境变量进行修改。有关编译 NVSHMEM 的更多信息,请参阅安装指南。有关运行时环境配置,请参阅环境变量部分。

NVSHMEM 的优势

NVSHMEM 将集群中多个 GPU 的内存聚合到一个 PGAS 中,从而能够在 CUDA 内核中进行细粒度的 GPU 到 GPU 数据移动和同步。

使用 NVSHMEM,开发人员可以编写包含通信和计算的长时间运行的内核,从而减少与 CPU 同步的需求。由于 GPU 上的线程 warp 调度,这些复合内核还允许计算与通信的细粒度重叠。NVSHMEM GPU 发起的通信减少了内核启动、CUDA API 调用和 CPU-GPU 同步产生的开销。减少这些开销可以显著提高应用程序工作负载的强扩展能力。

注意:在必要时,NVSHMEM 还提供了 CPU 端调用的灵活性,用于 CUDA 内核之外的 GPU 间通信。

消息传递接口 (MPI) 是最常用的可扩展高性能计算通信库之一。NVSHMEM 的一个关键设计原则是支持来自 CUDA 内核的细粒度、高度并发的 GPU 到 GPU 通信。在这种通信模式中使用传统的 MPI 发送和接收操作可能会导致严重的效率挑战。由于需要匹配发送和接收操作,可能会出现以下问题

  • MPI 实现可能会对消息传递中涉及的共享数据结构产生较高的锁定(或原子操作)开销。
  • 由 MPI 消息排序要求导致的序列化开销。
  • 协议开销,这是由于消息在接收方发布相应的接收操作之前到达造成的。

尽管已经努力通过使用细粒度锁定和每个进程多个网络端点来减少关键部分的开销,但发送和接收操作之间的匹配是 MPI 中发送-接收通信模型固有的,并且难以扩展到 GPU 呈现的高度线程化环境。相比之下,单边通信原语避免了这些瓶颈,因为它使发起线程能够指定完成数据传输所需的所有信息。单边操作可以直接转换为网络硬件公开的 RDMA 原语,或者转换为 NVLink Fabric 上的加载/存储操作。使用异步 API,单边原语也使程序更容易交错计算和通信,从而有可能实现更好的重叠。

GPU 发起的通信和强扩展

NVSHMEM 对 GPU 发起的通信的支持可以显著减少通信和同步开销,从而提高强扩展能力。

强扩展是指当处理器数量增加时,固定问题的求解时间如何变化。它是指通过增加处理器数量来更快地解决固定问题的能力。对于许多科学、工程和数据分析应用程序来说,这是一个关键指标,因为越来越大的集群和更强大的 GPU 变得可用。

当前在 GPU 集群上运行的最先进的应用程序通常将计算阶段卸载到 GPU 上,并依靠 CPU 使用 MPI 或 OpenSHMEM 管理集群节点之间的通信。依赖 CPU 进行通信限制了强扩展性,因为重复内核启动、CPU-GPU 同步、通信阶段 GPU 利用率不足以及计算阶段网络利用率不足会产生开销。其中一些问题可以通过重构应用程序代码以使用 CUDA 流重叠独立的计算和通信阶段来解决。这些优化可能会导致复杂的应用程序代码,并且随着每个 GPU 的问题规模变小,收益通常会减少。

随着问题被强扩展,执行的 Amdahl 分数,对应于 CPU-GPU 同步和通信的部分会增加。因此,最大限度地减少这些开销对于 GPU 集群上应用程序的强扩展至关重要。GPU 也被设计用于吞吐量,并且具有足够的状态和并行性来隐藏到全局内存的长延迟,这使得 GPU 能够有效地隐藏数据移动开销。遵循 CUDA 编程模型和最佳实践,并使用 NVSHMEM 进行 GPU 发起的通信,使开发人员能够利用这些延迟隐藏能力。