在大语言模型推理场景中,如何在显存受限的消费级显卡上运行超大参数模型一直是工程难题。传统方案依赖 CPU 介入的数据搬移:NVMe SSD 首先将模型权重加载至主机内存,再通过 PCIe 拷贝至 GPU VRAM,这一过程不仅占用 CPU 周期,还因额外的内存复制而浪费带宽。gpu-nvme-direct 项目展示了另一种可能:让 CUDA 内核直接与 NVMe 控制器通信,绕过 CPU 和系统内存,实现 GPU 自主的存储访问。
传统数据路径的性能瓶颈
常规 GPU 推理的存储访问路径遵循「NVMe → 主机 pinned 内存 → GPU VRAM」的层层递进模式。以 70B 参数模型为例,FP16 精度下模型体积约为 140 GB,单张 RTX 3090 的 24 GB 显存无法容纳完整权重,必须采用分层加载或量化策略。即便使用 Q4 量化将模型压缩至约 40 GB,频繁的层切换仍需要大量的权重加载操作。
这一路径的核心问题在于 CPU 成为了数据搬运的瓶颈。Linux 内核的 NVMe 驱动、文件系统栈以及 PCIe DMA 引擎全部运行在 CPU 侧,每字节数据至少经历两次内存复制:SSD 到主机内存、主机内存到 GPU VRAM。对于需要持续加载权重的推理任务,这种「双跳」架构带来的延迟远超 NVMe 本身的高带宽所能弥补的范围。
GPU 自主 NVMe 访问的架构设计
gpu-nvme-direct 项目实现了 GPU 内核直接向 NVMe 控制器发送命令的能力,其核心思想是将存储访问视为 GPU 可编程的 I/O 操作,而非必须委托给 CPU 的系统调用。该实现依赖以下技术组件:
PCIe BAR MMIO 映射:NVMe 控制器的寄存器空间通过 PCIe Base Address Register 映射到系统内存地址空间。传统上只有 CPU 可以访问这些 MMIO 区域,但通过适当的内核模块和驱动配置,GPU 也能获得对这些地址的访问权限。项目使用 PTX 指令集中的 st.mmio.sys 和 ld.mmio.sys 变体实现非缓存的 MMIO 读写操作。
GPU 原生的命令构造与提交:CUDA 内核内部直接构建 NVMe 提交队列条目,包括 READ 或 WRITE 命令、PRP(Physical Region Page)指针以及数据缓冲区的物理地址。构造完成后,通过 __threadfence_system() 确保所有内存操作对 PCIe 可见,然后直接写入 NVMe 控制器的 SQ Tail Doorbell 寄存器,触发命令执行。
轮询方式的完成检测:GPU 不依赖中断机制,而是通过 MMIO 读取完成队列条目,检测相位位的变化来判断命令是否完成。这种轮询模式避免了 CPU 中断处理的延迟,特别适合 GPU 并行执行大量 I/O 操作的场景。
消费级硬件的分层实现
NVIDIA 在消费级 GeForce 显卡上禁用了 PCIe P2P DMA 功能,这使得 GPU 与 NVMe 之间的直接 DMA 传输无法像专业数据中心 GPU 那样直接实现。项目的应对策略是提供三层降级方案,根据硬件能力和驱动支持程度选择合适的模式:
第一层(Tier 1)仅依赖 MMIO 操作,GPU 负责驱动 NVMe 的门铃寄存器和完成队列轮询,但数据缓冲区仍然驻留在主机端的 pinned 内存中。这一层不需要 P2P DMA 支持,已在华硕 ROG STRIX B450-F 主板上验证可实现 3.35 GB/s 的持续读取带宽,接近 PCIe Gen3 x4 的理论上限。
第二层(Tier 2)需要打补丁的 NVIDIA 开源内核模块,使数据缓冲区能够直接分配在 GPU VRAM 中。NVMe 控制器通过 DMA 将数据写入 GPU 显存,绕过主机内存,进一步减少延迟。
第三层(Tier 3)实现完整的 BaM 架构,包括队列结构和数据缓冲区全部位于 GPU 显存中,这是理论最优方案,但需要原生的 PCIe P2P 支持,目前在消费级硬件上不可用。
70B 模型加载的实测数据
项目作者使用消费级硬件完成了端到端验证:AMD Ryzen 7 5800X CPU 配合单张 RTX 3090 显卡,NVMe 采用西部数据 SN740 512GB(Gen4 设备在 B450 芯片组下降频至 Gen3 运行)。在 Q6_K 量化条件下,70B 模型流式加载达到 0.2 tokens/s 的生成速度,相比传统的 mmap 方式提升 33 倍。
这一数据揭示了一个关键洞察:虽然 NVMe-to-GPU 的直接带宽(3.35 GB/s)远低于 GPU 显存带宽(936 GB/s),但通过精细的分层调度和预取策略,仍可为超大模型提供可用的推理吞吐。瓶颈从「存储带宽不足」转变为「如何有效隐藏 I/O 延迟」,这为系统设计指明了方向。
工程落地的关键参数
若在类似硬件上复现该方案,以下参数值得关注:主板需选择支持 PCIe 稳定 BAR 映射的型号,B450 芯片组已验证可行;CUDA 版本推荐 13.1,驱动需要 590.48.01 以上;NVMe 控制器应支持至少 512KB 的 MDTS(Maximum Data Transfer Size),以减少命令提交开销;队列深度建议设置为 32,以充分隐藏单次 I/O 延迟。
适用场景与局限
该方案并非万能解药。对于已能完整加载至 VRAM 的模型(通常 30B 参数以下),传统方案的延迟更低。NVMe 直连的核心价值在于突破显存容量边界,让单卡可以运行远超显存容量的模型,同时保持「可用」的推理速度。典型应用包括:长时间长上下文推理的 KV cache 换入换出、多租户场景下的模型分片管理、以及需要频繁切换不同模型的开发调试环境。
从系统软件视角看,gpu-nvme-direct 证明了消费级硬件上实现 GPU 自主存储访问的可行性,为大模型推理的存储层次化提供了新的架构思路。随着未来消费级 GPU 对 P2P 功能的逐步开放,或 Linux 内核对 GPU MMIO 访问的原生支持,该技术的实用价值有望进一步释放。
参考资料
- GPU-NVMe-Direct 项目主页:https://github.com/xaskasdf/gpu-nvme-direct
- BaM: GPU-Initiated On-Demand High-Throughput Storage (ASPLOS 2023)