2. MAS介绍
2.1. 背景
在传统架构中,存储设备与 GPU 之间的数据交互必须以系统内存(Host RAM)作为中转站。 具体而言,文件数据需先从存储介质读取至系统内存,再经由系统内存拷贝至 GPU 显存(VRAM)。
这种基于内存中转的访问模式存在以下显著瓶颈:
传输路径冗长,端到端延迟高:数据需经历额外的中间拷贝环节,显著增加了整体的传输时延
内存资源挤占与系统干扰:该过程不仅额外消耗主机的系统内存,且极易受到主机端其他并发任务的干扰,导致传输速率受限
PCIe 带宽竞争加剧,性能易波动:数据需要在 CPU 与 PCIe Switch 之间往返传输(即先上行至内存,再下行至 GPU),极大地加剧了总线带宽的竞争,导致传输性能极不稳定
为了突破这一瓶颈,可引入 PCI 总线的原生特性:它允许同一总线上的两个设备间直接进行内存访问(DMA),此类事务被称为点对点(Peer-to-Peer,P2P)传输。 基于这一特性,GPU 显存能够直接被总线上的其他硬件设备(如 NVMe 存储设备)访问。 数据无需再绕道系统内存,从而从根本上消除了传输路径冗长、主机资源挤占以及 PCIe 带宽竞争等问题。
图 2.1 存储-GPU 传输路径对比
2.2. 基本原理
P2P 在软件层面面临的主要挑战在于:若要复用 Linux 现有的内核接口(如直接 I/O),参与 P2P 事务的设备内存必须拥有对应的 struct page 描述符。
为此,Linux 引入了 ZONE_DEVICE 内存区机制,旨在为设备驱动指定的物理地址空间提供 struct page 映射服务。
该机制的“设备”属性主要体现在:这些地址范围对应的页面对象永远不会被标记为“在线(online)”状态(即不混入系统公共内存池); 此外,在锁定(pin)内存以供读写时,系统必须持有针对该底层设备的引用计数,而不仅是页面自身的引用。
得益于此,由 struct page 描述的 GPU 显存能够像传统的主机物理内存(RAM)一样,直接交由 Linux 虚拟文件系统(VFS)进行无缝调度与处理,从而在内核层面彻底打通了 P2P 传输的软件链路。
2.3. 工作流程
MAS 特性由两部分组成,用于态的 mcFile.so 库和内核态的 GPU 驱动。MAS 功能没有单独的内核模块,直接集成在 GPU 驱动中。 存储设备的驱动,如 NVME 驱动,不需要修改。
图 2.2 工作流程
GPU 驱动加载时通过
devm_memremap_pages将 VRAM(BAR0)注册到ZONE_DEVICE。构建对应的 struct page。使用
O_DIRECT通过标准接口fopen打开需要读写的文件,获取文件句柄。将文件句柄注册到 mcFile 库。
使用
mcMalloc分配 VRAM,获得 VRAM 句柄。使用
mcFileWrite/mcFileRead发起操作,将文件句柄和内存句柄传入驱动。GPU 驱动通过 IOCTL 接口收到请求后,通过内核标准接口获得内存句柄对应的 struct page,并构造出
bio_vec。通过标准 VFS 接口发送 IO 请求。
VFS 会将这些 GPU 内存页当作普通主机 RAM 处理,然后将其传递给存储设备驱动程序。与普通 RAM 页的 IO 请求一样,无需对这些 GPU 内存页执行任何额外操作。
2.4. 内核依赖
本特性依赖于内核对 ZONE_DEVICE 的支持,使用前需要检查 CONFIG_ZONE_DEVICE 是否打开。
cat /boot/config-$(uname -r) | grep ZONE_DEVICE
CONFIG_ZONE_DEVICE=y
2.5. 使用步骤
MAS 功能默认是关闭的,GPU 内核驱动模块提供了模块参数 mas 控制此功能的开关。可以在安装驱动时通过如下方式打开。
sudo ./metax-driver-x.x.x.x-deb-x86_64.run -- --module-parameter="mas=1"
备注
模块参数存在 /etc/modprobe.d/metax-base.conf 里,如果安装后要关闭,可以手动修改此文件,将 mas=1 改为 mas=0。
因为一些问题和限制(参考 3 已知问题和限制),MAS 初始化过程中可能失败,可以通过如下方法检测 MAS 是否初始化成功。
cat /sys/class/mxcd/mxcd/layout/properties | grep mas
mas 1