使用GPU Direct RDMA优化基于GPU数据传输

本文章通过gptschools.cn翻译,原论文:Optimizing Data Movement for GPU-Based In-Situ Workflow Using GPUDirect RDMA

摘要

在大规模计算领域,GPU加速系统越来越占主导地位。与此同时,使用内存到内存的应用程序间数据交换的Direct技术已经成为利用这些大规模系统的有效方法。对于GPU而言,GPUDirect RDMA使得第三方设备(如网络接口卡)能够直接访问GPU内存,并且已在GPU之间的应用程序内通信中得到了采用。在本文中,介绍一种基于GPU的Direct技术的互操作框架,利用GPUDirect RDMA来优化数据传输。具体而言,我们从Direct技术的角度分析了GPU之间可能的数据传输路径的特征,并设计了一种最大化吞吐量的策略。此外,我们将这种方法作为Data Spaces数据分拨服务的扩展来实现,并在当前领先的GPU集群上进行性能和可扩展性的实验评估。实验结果表明,该设计提高了发送方和接收方的数据传输时间,分别提高53%和40%,并且多达256个GPU规模下,有出色的可扩展性。

引言

新兴的高性能计算系统普遍采用图形处理单元(GPU)以获得其巨大的计算能力和高能效。以2022年11月的数据为例,TOP500榜单上排名前十的系统中有七个拥有GPU。科学模拟和分析受益于GPU的并行性和能效 [12]。许多应用程序和工具,如LAMMPS [9]和ZFP [16],已发布了针对GPU优化的版本。

然而,对于松散耦合的Direct技术而言,仍存在巨大的I/O差距[15]。Direct技术通常由多个科学应用程序组成,这些组件应用程序在GPU / CPU上运行,并通过高速网络交换数据。尽管个别应用程序可以利用GPU,但在GPU之间和GPU-CPU之间的I/O交叉代码是以特定方式实现的,容易导致低效的性能。另一方面,最新的硬件特定技术,即GPUDirect RDMA(GDR)[3],在许多现代HPC系统上可用,并提供了性能改进的机会,但需要领域科学家具备深入的硬件知识和底层编程技能。

解决工作流程中组件之间的I/O的现有解决方案将设备(GPU)和主机(CPU)视为个体,并采用:设备⇀↽主机⇀↽网络的路径。可以看到,主机的参与并不重要,并且由于主机不必要的数据移动,会降低I/O性能。这种减速将在更大规模下加剧。此外,在组件之间进行I/O时涉及到主机需要开发人员使用低级别的GPU编程API(如CUDA、HIP等)在主机和设备之间传输数据。对于领域科学家来说,使用这些低级别的API进行编程并不简单,并且这种编程方法通常会导致仅具有互操作性和可移植性的特定解决方案的形成,特别是在涉及大量变量或复杂I/O模式的情况下。

将现有的Direct技术迁移到GPU上是许多科学计算社区的持续努力。图1说明了这个工作流迁移问题的挑战:某些组件已准备好在GPU上运行,而其他组件正在进行迁移或仍然有遗留问题。这种异构性使得不同迁移阶段组件之间的I/O管理变得复杂,并且使得即插即用几乎不可能。复杂的数据通信模式和大量的变量使情况变得更加糟糕。例如,MURaM工作流的I/O引擎[19]总共包含7个独立的过程,涉及50个一维变量、63个二维变量和34个三维变量。我们认识到,尽管在GPU和主机之间移动数据以及在主机缓冲区和网络之间进行常规通信仍然是一种解决方案,但在迁移过程中需要进行大量的重复代码重构工作,但仍然无法灵活地迁移到其他GPU生态系统上。

image-20240121201014391

图1:典型的基于GPU的Direct移植过程。主要已经移植到GPU上。其他组件正在移植、或者仍然保持CPU版本。组件之间的输入输出也必须根据数据源/目标进行更改。

基于这些观察结果,本文研究了几种适用于GPU应用程序之间的大规模数据交换的技术,并引入了一种通过主机绕过不必要数据移动路径的GDR设计。因此,我们提出了第一个基于GPU的Direct技术的可互操作I/O抽象,并将其作为Data Spaces[10]数据分段服务的扩展进行实现。本文的主要贡献如下:

  • 我们研究了几种适用于GPU应用程序之间的大规模数据交换的设计,针对Direct技术的特点提出了一种绕过主机降低I/O开销的GDR设计。
  • 我们提出了第一个基于GPU的Direct技术的可互操作I/O抽象,将其作为DataSpaces数据分段服务的扩展实现,降低了软件重构成本并在工作流迁移过程中实现了即插即用。
  • 我们在当前领先的GPU集群上使用合成和真实工作流进行了评估,运行了256个GPU,并且证明与基线相比,它们可以将发送者和接收者的I/O时间分别减少高达53%和40%。

背景

Direct 技术

传统的科学工作流模型首先将仿真数据写入持久存储,然后在稍后的分析或可视化过程中将其读入内存,这被定义为事后方法,因为可视化或分析是“事后”进行的[8]。随着计算吞吐量的增加,我们已经看到了这种方法的性能显著放缓[4,5,7,17]。另一种称为Direct技术,通过消除非必要存储节省大量的I/O。Direct模型中出现了两种范式:紧耦合方法和松耦合方法[15]。紧耦合范式如图2a所示,仿真和分析在同一个进程中运行,使用相同的计算资源集。它们在每次迭代中交替运行,共享存储在内存中的数据,并最终将精炼的结果输出到文件系统。至于松耦合范式,仿真和分析在它们各自的进程组中异步运行,每个进程组都有自己的资源,如下图所示。

image-20240121201226583

图2展示了Direct(In-situ)工作流的两种范例:(a) 紧密耦合的Direct(in-situ)工作流;(b) 松散耦合的Direct(in-situ)工作流。

image-20240121183021322

(a) GPU和网络接口卡(NIC)之间的原始数据流。红色路径只需要将数据暂存在一个主机缓冲区中,但需要由GPU/NIC或NIC/GPU进行顺序DMA注销和注册。蓝色路径允许GPU和NIC在两个主机缓冲区进行注册,但需要额外的内存复制操作。

image-20240121201815378

(b) GPU与NIC之间的GPUDirect数据流。GPU和NIC可以同时在同一个主机缓冲区进行注册。

image-20240121201914876

(c) GPU与NIC之间的GPUDirect RDMA(GDR)数据流。避免了CPU数据暂存。

图3展示了GPU和网卡(NIC)之间的数据流路径。

在图2b中,它们通过一个服务器在高速网络上交换共享数据,这需要额外的资源来管理数据转发。

松散耦合的in-situ工作流通过将计算任务以适当的粒度隔离来维持其灵活性和模块化性。我们将每个独立运行的计算任务定义为松散耦合组件。灵活性意味着可以根据每个组件的特性分别配置其运行规模,避免在整体资源分配下的低效率。此外,模块化支持新组件的方便插拔,这可以节省大量的开发成本,并实现更复杂的扩展。这两个特性通过利用现代高性能计算系统中配备的GPU为in-situ工作流提供了巨大的改进机会。将每个组件分配给最适合的硬件最终将提高工作流的整体性能。

GPU Direct技术

直接内存访问(DMA)在数据访问之前需要进行内存注册。GPU的DMA引擎需要将CPU内存区域注册才能实现异步数据移动,网络接口卡(NIC)也需要进行此注册才能在网络上传输数据。因此:

  • 如图3a所示,GPU和NIC要么按顺序注册同一个主机缓冲区,要么同时注册两个独立的主机缓冲区,但都需要进行额外的数据复制来进行GPU数据通信。取消注册/注册过程和额外的内存复制都可以总结为增加I/O延迟的DMA开销。 NVIDIA的GPUDirect技术消除了GPU和其他设备之间不必要的内存复制,减少了CPU开销,降低了延迟[3],从而显着增强了GPU的数据移动和访问能力。
  • 在CUDA 4.0中发布的初版GPUDirect使得GPU和NIC能够在CPU上注册同一个内存区域,避免了主机上的DMA开销,如图3b所示。
  • 从CUDA 5.0开始,GPUDirect RDMA(GDR)作为GPUDirect的扩展版本发布,支持任何第三方标准PCIe设备对GPU内存的注册。图3c说明了GPU和NIC之间直接数据交换的路径。

AMD的GPU也支持在其ROCm生态系统中的点对点直接技术,称为ROCmRDMA [2]。然而,在本文中,我们使用总称的GPUDirect RDMA (GDR)来指代GPU和NIC之间的所有直接数据交换解决方案。我们在本文的其余部分将重点关注具有CUDA编程生态系统和支持RDMA网络的NVIDIA GPU。

相关工作

过去十年来,高性能计算社区做出了大量贡献,通过GPUDirect技术在广泛使用的编程模型和网络基础设施中加速与GPU相关的I/O。Wang等人提出了MVAPICH2-GPU [26],这是第一个对基于CUDA的GPU进行优化的GPU-aware MPI实现。Potluri等人使用GPUDirect RDMA(GDR)升级了GPU-aware MPI库,并提出了一种混合解决方案,兼具GDR和基于主机辅助的GPU通信的优点[18]。Shi等人设计了基于GDR的低延迟GPU和主机内存之间的拷贝机制GDRCopy[22],提高了小消息传输的效率。作为领先深度学习框架的常用后端,NVIDIA NCCL[13]也在其通信例程集中支持了GDR。此外,还研究了简化GPU应用移植过程的编程框架。Kokkos[24]、RAJA[6]和SYCL[20]支持在其抽象中编写的应用程序的编译时平台规范。然而,无论是从工作流角度还是从数据移动优化或I/O抽象角度来看,研究工作都非常有限。ADIOS2[11]是一个高性能I/O框架,经常用作工作流中各组件之间的数据耦合器,并扩展为支持GPU感知的I/O[1]。然而,它的GPU I/O支持仅适用于基于持久性存储的二进制-Pack版本4(BP4)和BP5文件引擎。Zhang等人研究了CPU-GPU混合松耦合原位工作流中的数据布局不匹配,并提出了一种降低数据重组开销的解决方案[27]。然而,他们并没有优化GPU组件的数据移动路径。Wang等人提出了一个关于in-situ工作流中GPU感知数据交换的概念性概述[25],但他们只提出了一个初步的想法,既没有实现细节,也没有大规模定量评估。我们的工作与相关工作的区别在于我们是第一个在松耦合原位(in-situ)工作流中提供互操作的GPU感知的I/O抽象。我们在配备GPU的最新一代生产HPC系统上以最大规模对GDR设计进行了系统全面的评估。

设计

在本节中,我们讨论GPU应用间批量数据移动的基准设计和优化设计。如图1所示,工作流中的组件可以分为三类:暂存服务器、发送方和接收方。暂存服务器通常作为一个受限于内存的组件,负责存储中间共享数据并处理所有其他应用程序发起的异步I/O请求。因此,即使暂存服务器也可能在配备GPU的节点上运行,但出于容量和成本的考虑,CPU主内存仍然被选择作为其主要存储介质。发送方通常是在GPU上生成多维数据并将其发送到暂存服务器的模拟器。接收方通常是分析或可视化器,从暂存服务器获取数据并使用它。松耦合原位工作流只有一个暂存服务器组件,至少有一个发送方和一个接收方。在下面的子节中,我们分别讨论这两个部分。我们还提供了所提议的I/O框架的实现概述,并通过一段代码片段展示了其互操作性。

发送方

基准设计为了将GPU数据发送到暂存服务器,基准设计简单地使用CUDA内存拷贝从设备拷贝到主机,然后设置一个传统的CPU-CPU批量数据传输。这种直接的方法将批量I/O视为一个整体,将GPU到CPU和CPU到暂存服务器的数据传输连接在一起,这些传输在CPU上的元数据准备阶段后按顺序运行。在两个连接的I/O过程之间必须经过本节中介绍的DMA控制序列,这增加了总体延迟。虽然这种设计直观简单易于实现,但其弱点在频繁和连续的put请求时变得明显,因为每个请求都会引起固定的开销。

image-20240121182910928

图4. 发送方设计的示意图。

image-20240121182843815

图5. 接收方的数据对象重组。发送方的4个处理单元(PE)将本地的4x4的二维数组放入全局的8x8域中。接收方的2个PE期望得到一个8x8共享域的子集,分别是一个3x3的数组和一个3x2的数组。接收方的PE1需要找到数据对象A,复制内存行一次,然后找到数据对象C,复制内存行两次。接收方的PE2需要找到数据对象B和D,并相应地复制内存行。

流水线设计 我们能够通过将整个发送过程分成几个阶段并仔细分析它们之间的依赖关系,将独立任务重叠来优化基线设计。图4a显示了不需要额外先决条件的流水线设计。元数据是在将大量数据从GPU复制到主机时由主机准备的。此外,DMA操作部分重叠了发送方和分段服务器之间的连接设置。该设计利用了GPU和CPU的异步性,以充分利用发送过程不同阶段之间的潜在重叠。

GDR设计 一旦将GPU数据传输到分段服务器,中间阶段越少,性能就越好。通过在大规模数据传输中使用GDR,我们完全避免了主机的参与。图4b展示了简洁的GDR设计。在必要的元数据准备和连接建立阶段之后,数据直接从GPU内存发送到分段服务器。该设计中没有进行内存分配和DMA开销。

接收方

由于发送方设计的简单性,在接收方,除了用于灵活性的规模化的数据输入/输出,还引入了数据对象重组阶段,以及通过几何描述符指定的多维数据的随机访问。我们在本小节分别讨论这两个阶段。

数据对象重组 在将查询数据交付给用户之前,接收方的每个获取请求都必须经过数据重组阶段。图5通过一个例子展示了数据重组的必要性。一个二维数据域由两个应用程序共享,其中一个应用程序作为发送方具有四个处理单元(PE),另一个应用程序作为接收方具有两个PE。发送方将四个数据对象放入分段服务器,而接收方希望在每个PE中获取数据的子集。因此,接收方的每个PE必须找出原始数据对象,提取每个子集,并最终将子集重新组装为相应的连续数据对象。即使接收方查询整个域,只要两个应用程序在不同的规模下运行,将原始数据对象重新组合为查询连续数据对象仍然是必要的。

image-20240121181802395

数据对象重组的现有解决方案完全基于CPU。它通过迭代调用Memcpy()来一次将数据行沿着最低维度移动,以实现多维数据的重组。由于GPU应用程序中的数据目的地被转移到了GPU内存中,我们设计了一个CUDA核函数,通过利用GPU架构的内在并行性来加速数据对象重组任务。算法1描述了该核函数的详细内容。虽然一个单独的核函数只支持高达3维的数据对象重组,但可以为更高维数的数据多次迭代地启动。根据目标CUDA设备的能力,利用异步核函数启动实现并发。

image-20240121182659026

图6. 接收方设计的示意图。

大规模数据传输接收端的大规模数据I/O路径与发送端保持相同的选项:CPU-CPU传输以及从主机到设备或GDR的CUDA内存复制。因此,我们提出了三种接收端设计,结合了大规模数据传输和数据对象重组选项。图6a展示了基准设计,在主机上将接收到的数据对象重新组合到一个新的CPU缓冲区中,然后传输到GPU目的地。由于在主机上使用了两个缓冲区,并且数据对象重组本质上完成了它们之间的内存复制,因此这种设计没有产生DMA开销。混合设计采用传统的I/O路径,但使用CUDA内核进行数据对象重组。它只持有一个缓冲区,用于从暂存服务器接收数据并传输到GPU,但是它的DMA开销部分与CUDA内核计算重叠,因为通常会接收到多个数据对象,并且后续工作是异步完成的。GDR设计保持清晰,如图6b所示。它没有CPU参与,数据对象重组由CUDA内核完成

image-20240122090827310

图7:DataSpace-GPU的架构。现有模块被扩展以在异构内存管理层下支持GPU计算和存储。

实施和互操作性

本文的设计是在现有的DataSpaces暂存框架中实现的,作为对支持in-situ工作流中GPU组件之间的数据交换的扩展。

图7以示意概述了Data Spaces-GPU。它通过重用数据传输、索引和查询的现有组件来实现。应用客户端的数据对象存储模块的GPU内存扩展利用了Margo [21]通信层的GDR能力。当目标GPU具备能力时,对象组装模块添加了支持同时启动CUDA内核的功能。所有GPU扩展由异构内存管理层组织,该层确定用户数据是位于CPU还是GPU上。为了最小化软件移植成本,我们为CPU和GPU I/O设计了一组统一的API,以解决与传统CPU工作流的互操作性问题。图8展示了一个代码示例,比较了使用或不使用我们的框架进行单变量I/O过程时所需的代码行(LOC)更改。设置适当的元数据后,只需要一行代码来发送或接收CPU数据。当数据位于GPU上时,我们需要计算数据大小,管理CPU内存缓冲区,并在发送端和接收端分别处理CUDA内存复制。对于一个单变量,每个方向需要添加约10行代码,没有进行任何性能优化的数据移动。然而,使用Data Spaces-GPU,唯一需要做的工作是将CPU指针更改为GPU指针,不需要额外的代码,这样可以节省巨大的软件移植成本,特别是当需要通信的变量较多或通信模式较复杂时。因此,DataSpaces-GPU在整个工作流移植过程中实现了逐步过程的I/O插拔功能。

image-20240122090912585

评估

本节中,我们以时间到解决方案和可扩展性两方面对所提出的GDR设计与传统基于主机的设计进行评估。使用合成工作流模拟器测试端到端基准,并在由LULESH-CUDA [14]和ZFP-CUDA组成的真实科学工作流上进行弱扩展实验。

我们的合成工作流仿真器使用两个应用程序代码,即写者(writers)和读者(readers),来模拟实际的松散耦合原地工作流中应用程序之间的数据移动行为。写者生成模拟数据并将其发送到暂存服务器,而读者从暂存服务器获取数据,然后进行一些分析。在我们的实际工作流实验中,LULESH是将数据写出的模拟程序,ZFP是读者。这些数据以X × Y × Z比例的三维笛卡尔网格格式进行组织,两个工作流都采用相同的比例。

所有实验都在National Energy Research Scientific Computing(NERSC)的Perlmutter超级计算机的Phase 2 GPU节点上进行。Phase 2 GPU节点使用了一颗AMD EPYC 7763(Milan)64核处理器和160GB的DDR4 RAM。每个节点配备了四个NVIDIA Ampere A100 GPU和四个Slingshot-11 Cassini网络接口卡(NIC)。所有节点都运行带有Cray Slingshot-11 cxi支持的libfabric-1.15.0。所有四个NIC都被充分利用,并且均匀映射到每个节点上的处理单元(PE)。启用了并发的CUDA内核启动,并将最大并发内核启动数设置为默认值32。在接下来的章节中,所有测量时间指的是保证消息发送到目标的阻塞I/O函数的墙钟时间。所有测试运行已经执行了三次,并报告了平均结果。

表1. 端到端基准实验的实验设置配置

image-20240122092922352

image-20240121182201106

图9. 随着消息大小增加,提出的设计在每次I/O迭代中的性能比较。

端到端基准实验

该实验通过使用第4节介绍的不同设计方案,比较了应用程序和暂存服务器之间不同消息大小的I/O性能。表1详细列出了这个实验中所有测试案例的设置。为了减轻迭代干扰,我们将I/O频率设置为2秒。我们选择的消息大小从8MB开始评估,这是典型的细粒度域分解中每个并行PE中单个变量的最小数据大小。

图9a分别呈现了写者和读者的基准结果。总体上,尽管GDR被设计为优化与GPU之间的小型和频繁通信,但它在大批量数据传输方面的性能优于其他涉及主机的设计。在写者一侧,基线方法和流水线方法显示出几乎相同的趋势,这意味着在大规模数据传输中发送元数据的开销几乎可以忽略不计。与基线方法和流水线方法相比,GDR方法在8MB大批量传输时减少了53%的投放时间,在发送1024MB消息时仍然保持了34%的减少。

在读者一侧,混合方法和GDR方法相比基线的获取时间减少了28%和33%。GDR方法始终略优于混合方法,因为它避免了第2.2节中引入的DMA开销。两种方法都使用CUDA内核进行数据对象重新组装,而不是主机的Memcpy()函数,这主要contributor了性能的提升。图9b从整体I/O时间中提取并比较了数据对象重新组装的性能。随着消息大小的增加,CUDA内核将数据对象重新组装的任务加速了多达90倍。通过利用CUDA设备的异步内核执行特性,同时启动内核并等待所有内核完成的栅栏,甚至可以实现高达6000倍的加速。

表2.流体力学工作流的数据域、核心分配和分析数据量的实验设置配置

数据域512 × 512 × 512768 × 768 × 7681024 × 1024 × 10241280 × 1280 × 12801536 × 1536 × 1536
LULESH-CUDA核心数 / GPU数 / 节点数8 / 8 / 227 / 27 / 764 / 64 / 16128 / 128 / 32256 / 256 / 64
ZFP-CUDA核心数 / GPU数 / 节点数8 / 8 / 227 / 27 / 764 / 64 / 16128 / 128 / 32256 / 256 / 64
分析核心数 / 节点数4 / 116 / 432 / 864 / 16128 /32
总分析数据量 (3个变量,10个I/O迭代)30 GB60 GB120GB240GB480GB
I/O迭代频率每100次计算迭代

image-20240121182336096

图10. LULESH工作流中每个I/O迭代的I/O时间在提出的设计中的弱扩展性比较。

真实的科学工作流

除了基于合成工作流模拟器的评估外,我们还将我们提出的设计应用于基于CUDA的冲击流体力学模拟工作流中。我们使用LULESH-CUDA组件进行模拟,该组件生成3D数据并将其发送到分析服务器。为了进行分析,ZFP-CUDA组件从分析服务器获取数据,对其进行压缩并写入持久存储。我们从13个变量中选择了三个标量数据字段(能量,压力,质量)来执行应用间的数据交换。我们的流体力学工作流测试的实验配置如表2所示。由于LULESH只支持立方PE增量,我们选择了8、27、64个核心进行评估,与GPU的映射比为1:1,与节点的映射比约为4:1。我们选择网格域的大小,使得每个核心被分配一个大小为256×256×256的空间本地域。我们保持每个LULESH/ZFP核心的数据量相同,以在本次评估中进行弱扩展性测试。

图5.1比较了弱扩展性工作流中提出的设计与固定比例LULESH/ZFP资源与分析服务器的设计。与其他设计相比,GDR设计在连续发送数据字段时仍然需要的时间少了约24%,同时在获取数据字段方面比基线设计和混合设计好了约40%和约17%。随着整体问题规模和总资源的增加,各种设计的I/O时间保持相对稳定。随着资源数量的增加,几乎没有引入额外的开销,这表明所有提出的设计在解决更大规模的问题时具有良好的可扩展性。通过合成工作流和真实的科学工作流评估,我们可以推断出,在GPU应用程序之间的数据移动方面,直接从GPU内存到RDMA启用的网络进行数据移动的基准设计在任何规模下性能都很差,因为它采用了顺序的设备→主机→网络路径。通过在发送方实现管道I/O设计,并在接收方应用CUDA内核对数据对象重新装配,可以提高性能,但仍然涉及了不必要的主机操作。相反,我们的GDR设计实现了GPU内存与RDMA启用的网络之间的直接数据传输,相比基线设计,可减少高达53%的I/O时间。此外,我们基于GPU的原位工作流的I/O抽象与传统基于CPU的工作流共享相同的API,从而最大程度地减少了软件移植工作。总之,我们的GDR I/O优化可以有效减少科学工作流中GPU组件之间的数据交换开销,同时保持与传统基于CPU的应用程序的互操作性。

结论和未来工作

GPUDirect RDMA已经成为一种有效的优化方法,用于在GPU之间进行节点间通信,但目前只有为单个应用程序设计的I/O基础设施采用了这种方法。在本文中,我们提出了一种新颖的设计,将GPUDirect RDMA应用于GPU应用程序之间的大数据传输。此外,我们还提出了第一个用于基于GPU的原位工作流的可互操作I/O抽象,简化了GPU工作流程的移植过程,并通过统一接口实现了逐步插拔功能。我们基于Data Spaces框架实现了所提出的解决方案,并在NERSC Perlmutter系统上进行了评估。我们的实验结果,使用了合成和真实的GPU工作流程,证明了所提出的解决方案在发送方和接收方分别能够提供高达53%和40%的I/O改进,同时在256个GPU上能够保持很好的可扩展性。作为未来的工作,我们计划研究我们的设计在其他网络硬件(如Mellanox EDR和HDR互连)上的性能可移植性。我们还计划在我们的工作流I/O抽象中为AMD GPU提供全面支持。