GPU-Initiated I/O
导言
把 SSD 数据送进 GPU,最直观的优化似乎是“绕过 CPU”。但这句话混合了两个不同问题:数据是否经过 CPU 内存,以及 I/O 请求究竟由 CPU 还是 GPU 发起。NVIDIA GDS 解决前者,BaM 进一步改变后者;代价是原本由 CPU 承担的队列管理、并发和缓存压力转移到了 GPU。
本文整理 DaMoN 2025 论文 Path to GPU-Initiated I/O for Data-Intensive Systems:先沿 Figure 1 比较五条 GPU-centric Storage 路径,再还原 BaM、GDS 与 SPDK 的实验边界。核心结论不是“GPU 发起一定更快”,而是系统应根据 CPU、GPU、PCIe、SSD 与数据复用状态,选择由谁支付 I/O 控制成本。
如果只记住一句话,可以记住这句:GPU-initiated I/O 消除的是 CPU 在请求热路径上的职责,不是 I/O 本身的资源账单。
两个容易混淆的问题¶
传统数据路径分两段:CPU 先把数据从 SSD 读入 CPU Memory,再把它复制到 GPU Memory。只要工作集装不进 GPU 或 CPU 内存,这条路径就会不断重复,GPU 也可能因为下一批数据尚未到达而停顿。
“GPU-centric”至少包含两条彼此独立的轴线:
- 控制路径:谁创建并提交 NVMe 请求,谁轮询或接收完成通知。
- 数据路径:Payload 是否经过 CPU Memory,最终落到 CPU Memory 还是 GPU Memory。
由此会得到几个乍看反常、但很重要的组合:
- GPU 可以先调用文件 API,真正访问 SSD 的仍是 CPU,数据也仍经过 CPU Memory;GPUfs 与 ActivePointers 属于这一类。
- CPU 可以负责完整 I/O 控制,数据却通过 PCIe P2P 直接进入 GPU Memory;GDS 属于这一类。
- GPU 可以自己提交 NVMe 请求,并让 SSD 通过 PCIe P2P 把数据送入 GPU Memory;BaM 才属于这一类。
所以,“直接进入 GPU Memory”不等于“由 GPU 发起”,而“由 GPU 发起”也不等于初始化阶段完全不需要 CPU。
五条数据路径¶
下面的 Figure 1 是整篇论文最重要的认知锚点。图中数字表示一次读取的操作顺序;论文把第一条编号箭头从 CPU 发出的方案称为 CPU-initiated,其余称为 GPU-initiated。读图时还要同时观察 Payload 最终是否绕开 CPU Memory。
传统路径:CPU 包办控制与中转¶
传统方式由 CPU 发起读取,SSD 先 DMA 到 CPU Memory,CPU 再把数据复制到 GPU Memory:
这条路径的优点是软件栈成熟,文件系统、页缓存、预处理和错误处理都由 CPU 生态承接。缺点也很直接:CPU Memory 多做一次中转,CPU 还要负责分块与搬运调度。
GPUfs 与 ActivePointers:GPU 写 I/O 代码¶
GPUfs 把 open()、pread() 一类接口带进 GPU Kernel,对应提供 gopen()、gread()。ActivePointers 在此基础上增加类似 mmap() 的 gvmmap(),用软件地址转换和 GPU Page Cache 支持更自然的虚拟地址访问。
它们改善的是可编程性:应用不必在 CPU 侧写大量喂数代码,GPU Kernel 可以主动请求文件数据。但真正访问存储设备、把数据送入 CPU Memory,再复制到 GPU Memory 的仍是 CPU。换句话说,请求意图来自 GPU,设备 I/O 仍由 CPU 执行。
论文也提醒读者不要直接拿 GPUfs 的旧实验外推现代 NVMe 性能。GPUfs 在 2014 年使用 7200 RPM 机械硬盘;其顺序读取平均只比高度优化的 CUDA 方案慢约 5%,主要证明的是可编程性代价可控,而不是现代 SSD 上的性能上限。1
GDS:绕过 CPU Memory¶
NVIDIA GPUDirect Storage(GDS)利用 PCIe Peer-to-Peer,让 NVMe SSD 直接把数据传到 GPU Memory:
CPU Memory 从 Payload 路径中消失了,但 CPU 仍负责文件系统、I/O 编排与请求提交。因此 Figure 1 把 GDS 归为 CPU-initiated、GPU-direct Data Path。
这一区分也解释了 GDS 的资源形态:它不需要用 GPU SM 管理 NVMe 队列,却可能消耗较多 CPU。论文引用的既有研究还显示,GDS 的微基准优势不必然转化为本地 ResNet-50 训练吞吐提升;若训练本身不受存储限制,缩短存储路径主要改善 CPU 利用率,而不是总用时。1
BaM:GPU 敲响 NVMe Doorbell¶
BaM(Big accelerator Memory)把 NVMe Queue Pair 放进 GPU Memory,GPU Thread 可以直接写 Submission Queue,并敲响 NVMe Doorbell。SSD 完成读取后,再通过 PCIe P2P 把数据送入 GPU Memory:
CPU 仍需在启动阶段连接 NVMe、建立 Queue Pair 和准备映射,但不再参与每次请求的发送。BaM 还提供数组式高层 API:GPU Kernel 像访问一个映射到存储设备的数组一样取数,重复 Offset 可以命中 GPU 侧软件缓存。
真正困难的是并发。一个 GPU 可能运行数千个 Warp,而 SSD 常见可用 Queue Pair 只有 32 到 128 个。BaM 让一个 Warp 共享 Queue Pair,由 Lane 0 选择队列,再把多个 Warp 轮转映射到有限的队列上。CPU 热路径被移除后,队列竞争、请求生成与缓存占用并没有消失,而是落到了 GPU。
GMT:在三层之间做选择¶
GMT(GPU Orchestrated Memory Tiering)在 BaM 上增加 GPU Memory、CPU Memory 与 SSD 三层层次结构:
- SSD 与 GPU Memory 之间复用 BaM;
- SSD 与 CPU Memory 之间使用用户态 NVMe 驱动
libnvm; - CPU Memory 与 GPU Memory 之间对小传输使用
cudaMemcpyAsync,其余使用 Zero-copy。
GMT 的目标不是坚持所有数据都绕开 CPU Memory,而是让 GPU 根据数据位置与 Page Placement Policy 决定路径。它在高复用工作负载中最多减少 80% 的存储访问;但三层查找与迁移本身有显著开销,复用不足时甚至可能比 BaM 更慢。这个数字来自 GMT 自己的 PCIe Gen3、消费级 SSD 和 A100-40GB 设置,不能直接当作另一套系统的预期收益。1
把五条路径放在同一边界下,可以得到下面的对象账本:
| 方案 | 首个请求来自 | SSD Payload 路径 | CPU 的主要职责 | GPU 的新增职责 | 抽象 |
|---|---|---|---|---|---|
| Conventional | CPU | SSD → CPU Memory → GPU Memory | 请求、完成、中转 | 消费数据 | File/Buffer |
| GPUfs / ActivePointers | GPU | SSD → CPU Memory → GPU Memory | 实际设备访问与中转 | 发出文件或映射访问意图 | File / Mapped File |
| GDS | CPU | SSD → GPU Memory | 文件系统与完整 I/O 控制 | 消费数据 | File |
| BaM | GPU | SSD → GPU Memory | 初始化设备与 Queue Pair | 请求、完成、Queue Pair 共享、Cache | Array |
| GMT | GPU | 按命中层级选择 | CPU 层缓存与部分搬运 | 三层调度、BaM 路径与 Cache | Tiered Memory |
这张表揭示了一个比“少一次拷贝”更稳定的判断标准:优化路径时必须分别计算控制面由谁执行、数据面经过哪里、缓存状态放在哪里。
BaM 与 SPDK 的对照¶
论文接着问了一个很实际的问题:既然 BaM 是 GPU-centric 方案中的高性能代表,它和成熟的 CPU-centric 用户态 NVMe 栈 SPDK 相比,到底能做到什么程度?作者还加入 GDS,形成三种资源分工的对照:BaM 偏 GPU、GDS 偏 CPU、SPDK 使用少量 CPU 但数据先到 CPU Memory。
实验边界¶
这不是端到端模型训练或数据库查询,而是一组 Random Read Microbenchmark。关键条件如下:
| 维度 | 设置 |
|---|---|
| Server | Gigabyte G292-Z20 |
| CPU / DRAM | AMD EPYC 7402P 24-Core;8 × 32 GB DDR4-2400 |
| GPU | NVIDIA Tesla V100-16GB,PCIe Gen3 |
| SSD | 4 × 1 TB Samsung 980 PRO,SSD 为 PCIe Gen4 |
| OS | Ubuntu 20.04;为兼容 BaM/libnvm 使用 Linux 5.8 |
| BaM | Commit d20ef4a;CUDA 12.6;每设备 128 Queue Pair,Queue Depth 1024 |
| GDS | MLNX_OFED 5.8;16 个 CPU Thread;每线程 10 GB 文件 |
| SPDK | 24.09,启用 LTO;2 个逻辑 CPU,Queue Depth 256 |
| Workload | SSD 全盘顺序写入预处理后执行 Random Read;每项运行 5 次,报告均值与标准差 |
三套方法使用各自原生基准工具:BaM 用 nvm-block-bench,GDS 用 gdsio,SPDK 用 bdevperf。这样能测到各接口接近自身最佳状态,却也意味着线程数、Queue Depth、缓存与计时方式并不完全同构。论文把复现实验脚本放在 karlowich/bam-eval。1
带宽说明了什么¶
Figure 3 左侧使用四块 SSD,右侧只用一块。黑色虚线分别标出 PCIe 与 SSD 的理论上限;橙色 BaM、蓝色 GDS、粉色 SPDK 展示报告带宽,带 PCIe 后缀的线来自链路监控。
四盘实验给出三个关键观察:
- BaM 在 I/O Size 达到 32 KiB 后填满 V100 的 PCIe Gen3 链路。4 KiB 与 8 KiB 时,BaM 大致追平 SPDK;16 KiB 后 SPDK 继续扩展,BaM 逐渐受 GPU 侧 PCIe Gen3 限制。
- SPDK 展示了 SSD 阵列尚未耗尽的上限。四盘可达到约 25 GB/s,但 BaM 与 GDS 经过 V100,只能受 PCIe Gen3 ×16 的约 16 GB/s 理论链路约束。
- GDS 在这套机器上没有填满 PCIe。作者把主要原因推测为 EPYC 7402P 的多线程能力弱于原 BaM 论文使用的 EPYC 7702;这是基于硬件差异的解释,不是实验直接隔离出的因果结论。1
单盘时,BaM 与 SPDK 在 512 KiB 以前几乎重合,4 KiB 下 BaM 还略高。512 KiB 之后,橙色报告值突然超过链路上限,并不代表 SSD 真的获得百 GB/s 带宽:nvm-block-bench 开始重复请求相同 LBA,BaM 的 GPU Cache 命中后不再产生 PCIe 流量。这部分只能证明缓存生效,不能用来证明存储带宽。
Figure 3 没有证明什么
Figure 3 证明的是给定硬件、工具和 Random Read 参数下的接口带宽,不是端到端训练或查询加速比。SPDK 的数据还要从 CPU Memory 搬到 GPU,论文没有把这一步加入图中;BaM 与 GDS 的安装复杂度、GPU Kernel 可用计算资源、真实预处理和访问局部性也没有被同一张图量化。
隐藏的资源账单¶
带宽相近不代表成本相近。论文用 dcgmi 和 top 观察资源利用率:
- BaM:占满整个 GPU,同时占满 1 个逻辑 CPU;
- GDS:没有观察到 GPU SM 利用,但占满 16 个逻辑 CPU;
- SPDK:占满 2 个逻辑 CPU,带宽不低于另外两者,但还需要后续 CPU-to-GPU 搬运。
这正是论文最有价值的结果。BaM 可以不让 CPU 进入每次 I/O 的请求路径,却需要大量 GPU Thread 和 GPU Memory 来制造足够并发。对于昂贵的 V100/A100 一类加速器,如果计算 Kernel 本来已经接近满载,用整块 GPU 喂 SSD 未必比用两个 CPU Thread 更划算。
反过来,如果 GPU 正在等数据、CPU 又是系统瓶颈,那么把空闲 SM 用于生成 I/O 请求就可能合理。BaM 的优势不是抽象意义上的“更直接”,而是把可用但闲置的 GPU 资源换成更短的请求路径。这是基于论文结果形成的系统设计判断,而不是论文测得的通用加速比例。
扩展与拓扑¶
在 4 KiB Random Read 下,BaM 只要有足够多 GPU Thread,就能在一到三块 SSD 上追平 SPDK;加入第四块 SSD 后不再线性扩展,性能略低于 SPDK。论文推测,V100-16GB 无法提供足够大的 BaM Cache 和请求规模来填满四盘;原 BaM 实验使用的是 A100-80GB。
拓扑也会影响小 I/O。作者把 SSD 放在与 GPU 相同或不同的 PCIe Root Complex 下,在 Queue Depth 2 时测到 512 B 到 4 KiB 的 IOPS 差异最高约 33%;I/O Size 达到 8 KiB 后,额外路径延迟被更大的传输摊薄,差异消失。这个结果说明:GPU Direct 并没有取消 PCIe 拓扑,低并发、小 I/O 尤其需要检查 Root Complex 与 PCIe Switch 的位置。
怎样选择路径¶
论文没有给出一个永远获胜的实现,反而把选择条件说得更清楚了。下面是结合论文证据形成的工程判断,不是论文已经完成的端到端选型实验。
- 数据能常驻 GPU 或 CPU Memory:先用预取与复用减少磁盘访问,直读 SSD 不一定是主矛盾。
- GPU 已经满载计算:优先考虑 GDS 或 CPU-centric I/O,把 GPU 留给模型和查询 Kernel;同时确认 CPU 是否足以持续供数。
- GPU 因等待数据而空闲、CPU 又紧张:BaM 的 GPU-initiated 路径更值得评估,但要把 SM、显存、Queue Pair 和 Cache 纳入预算。
- 页面复用率高:GMT 的三层缓存可能减少 SSD 访问;复用不足时,额外层级可能得不偿失。
- 数据来自远端存储:论文所述 BaM 与 GMT 尚不支持 Network I/O,GDS 则已有远端路径;本地 NVMe 结论不能直接搬到对象存储或分布式文件系统。
实践中至少应同时报告以下指标,而不是只看 GB/s:
- 端到端 Step/Query Latency 与 Throughput;
- CPU Core、GPU SM、GPU Memory 与 Host Memory 占用;
- SSD IOPS/Bandwidth、PCIe Traffic 与实际 Cache Hit Rate;
- 请求大小、Queue Depth、访问局部性与并发计算重叠;
- 初始化约束、Kernel/Driver 版本、故障回退与集成成本。
仍未解决的问题¶
论文最后留下的不是某个更快的固定路径,而是三个系统问题。
文件还是数组¶
GPUfs、ActivePointers 与 GDS 保留 File Abstraction,容易承接多文件 Dataset 与现有生态,但文件系统开销不低。BaM 与 GMT 使用 Array Abstraction,便于 GPU Kernel 直接索引,却隐含数据顺序与邻近访问;对没有邻近性的工作负载,这种抽象未必自然。
CPU 与 GPU 能否动态协作¶
更合理的目标可能是 Resource-aware Hybrid I/O:GPU 忙时由 CPU 发起,GPU 闲时由 GPU 发起,并根据 PCIe、NVLink 与 SSD 的实时瓶颈切换。难点在于 CPU Memory 与 GPU Memory 之间如何共享或划分 NVMe Queue,怎样保证完成顺序、Cache 一致性与故障回退。
GMT 虽然混合了 CPU、GPU 与 SSD 三层,但其 Policy 主要围绕页面位置,并没有根据 CPU/GPU 利用率动态选择请求发起者。
如何进入真实框架¶
BaM 的实验需要旧 Linux Kernel 与特定 GPU Driver 组合;GDS 又依赖 MLNX_OFED、NVIDIA Driver、CUDA、nvidia-peermem 的安装顺序。论文认为,GPU-centric I/O 如果长期停留在专用 Demo 或单一框架补丁中,很难进入 PyTorch、JAX 与 GPU Database 的普通数据路径。
作者提出的方向是扩展 xNVMe 一类统一接口,让 CPU-centric 与 GPU-centric Backend 共享更稳定的集成层,再用 TPC、训练和推理等复杂负载做端到端评价。这个方向截至论文发表时仍是研究建议,不是已有实现。
总结¶
回到开头的问题:GPU 直读 SSD 的关键从来不只是删掉一个 CPU Memory Box。
Figure 1 把控制路径和数据路径拆开后,五种方案的差异就很清楚了:GPUfs 与 ActivePointers 把文件意图放进 GPU,GDS 让 Payload 绕过 CPU Memory,BaM 让 GPU 真正提交 NVMe 请求,GMT 再把 CPU Memory 放回可选择的缓存层。
实验进一步表明,BaM 能在一到三块 SSD 上追平 SPDK,也能在大 I/O 下填满 GPU 的 PCIe Gen3;但这个性能需要整个 GPU 与大量 GPU Memory 支撑。GPU-initiated I/O 不是消灭成本,而是重新分配成本。因此下一步真正值得验证的,不是“能否完全绕过 CPU”,而是能否让 CPU 与 GPU 根据实时利用率共同承担 I/O,并在真实训练或查询中获得端到端收益。
参考资料¶
- Karl B. Torp, Simon A. F. Lund, Pınar Tözün. Path to GPU-Initiated I/O for Data-Intensive Systems, DaMoN 2025. 本文的 Figure 1、Figure 3、实验设置与主要结论均取自该论文。
- Karl B. Torp et al.
bam-eval:论文实验的复现代码与 Artifact。 - Zaid Qureshi et al. GPU-Initiated On-Demand High-Throughput Storage Access in the BaM System Architecture, ASPLOS 2023.
- Mark Silberstein et al. GPUfs: Integrating a File System with GPUs, ACM TOCS 2014.
- Sagi Shahar et al. ActivePointers: A Case for Software Address Translation on GPUs, 2018.
- Chia-Hao Chang et al. GMT: GPU Orchestrated Memory Tiering for the Big Data Era, ASPLOS 2024.
- NVIDIA. GPUDirect Storage: A Direct Path Between Storage and GPU Memory.
- SPDK: Storage Performance Development Kit.

