Tutti 源码阅读(二):GPU 如何直接驱动 NVMe 队列
Tutti 最具辨识度的代码位于运行时以下:自定义 snvme 内核模块建立受控 NVMe queue pair,libnvm 管理设备资源,GPU kernel 批量写 SQE、更新 doorbell 并轮询 CQE。数据通过 PCIe P2P DMA 在 SSD 与 HBM 之间移动,CPU 不再逐条提交 I/O。 本文沿一次读请求下潜,分析为什么主线 Linux NVMe 驱动不够、控制面与数据面如何分离、GPU 如何构造命令,以及条带化和 layer-wise overlap 怎样落实到代码结构。 项目源码:xPU-IO/Tutti。 一、为什么需要自定义 snvme NVMe 控制器的数据面并不复杂:主机写 Submission Queue,更新 MMIO doorbell,设备执行 DMA,再把 Completion Queue Entry 写回内存。 问题是 Linux 主线 NVMe 驱动没有向普通应用提供一套稳定机制,用来同时完成: 创建应用独占或受控的 I/O queue pair; 将 SQ/CQ 放入可被应用或 GPU 访问的固定内存; 把对应 doorbell BAR 页安全映射给应用; 将 GPU HBM 注册成 NVMe 可 DMA 的 peer memory; 允许应用自行轮询 CQ,而不经过每请求系统调用。 传统 read、io_uring 或 GDS 可以缩短部分路径,但 NVMe 队列仍主要由内核或 CPU 侧库控制。Tutti 要让 GPU 成为请求生产者,因此需要一个负责授权与建图的内核控制面。 ...