← 返回信息流
AI 资讯Hacker News·1 天前

Linux下将Nvidia显卡显存用作交换空间

原标题:Use your Nvidia GPU's VRAM as swap space on Linux

速览

该技巧允许在Linux系统中将Nvidia GPU的VRAM配置为swap交换空间。当系统物理内存不足时,可利用闲置的显存来暂存数据,从而避免OOM错误。这对于显存充裕但内存受限的AI开发或计算环境具有实用价值。

AI 深度解读

在 Linux 上使用 NVIDIA GPU 的显存作为 Swap 空间

背景

在笔记本电脑领域,尤其是那些采用板载内存(soldered memory)且无法升级内存的机型中,物理内存(RAM)的容量往往成为性能瓶颈。当系统内存耗尽时,Linux 内核通常会将数据交换(swap)到 SSD 上。然而,SSD 的读写速度远低于内存,频繁的交换操作会导致严重的性能下降和延迟。

与此同时,许多配备独立显卡(如 NVIDIA RTX 系列)的笔记本电脑拥有大量的视频随机存取存储器(VRAM)。例如,一张 RTX 3070 笔记本显卡可能拥有 8GB 甚至更多的 VRAM。在大多数日常使用场景中,这部分显存并未被完全利用。

为了解决这一资源错配问题,开发者 Sean Lobjoit(GitHub ID: c0dejedi)发布了一个名为 nbd-vram 的工具。该工具允许 Linux 用户将 NVIDIA GPU 的 VRAM 作为交换空间(swap space)使用,从而显著增加系统可寻址的内存总量,缓解物理内存不足带来的压力。

核心内容

nbd-vram 的核心设计理念是绕过 NVIDIA 驱动中对消费者级 GPU 的直接内存访问限制,通过一种无需编写内核模块的架构,将 GPU 显存转化为标准的块设备。

技术架构与数据路径

该方案由一个小型守护进程(daemon)驱动,其工作流程如下:

  1. 显存分配:守护进程通过 CUDA 驱动 API 分配 VRAM。
  2. 块设备暴露:利用 NBD(Network Block Device,网络块设备)协议,通过 Unix 套接字(Unix socket)将分配的显存暴露为块设备。
  3. 内核连接:Linux 内核中内置的 nbd 驱动程序连接到该套接字,并在 /dev/nbdX 处暴露设备。
  4. 交换功能:此时,/dev/nbdX 就像一个普通的交换设备一样,可以被内核的交换子系统使用。

数据路径详解: 内核交换子系统 -> /dev/nbdX -> NBD 内核驱动 -> Unix 套接字 -> nbd-vram 守护进程 -> cuMemcpyHtoD/cuMemcpyDtoH(CUDA 内存拷贝) -> GPU VRAM。

为什么选择 NBD 方案?

在实现这一功能时,开发者尝试了两种“显而易见”的方法,但均因 NVIDIA 驱动的限制而失败:

  1. 使用 nvidia_p2p_get_pages_persistent: 这种方法旨在将 VRAM 页面固定在 BAR1 区域,以便 CPU 可以通过 ioremap_wc 直接访问。然而,现有的所有尝试都撞上了同一堵墙:在消费级 GeForce GPU 上,NVIDIA 驱动会返回 EINVAL 错误。无论是持久化还是非持久化变体,无论标志位如何设置,该功能仅在 Quadro 或数据中心 SKU 级别受支持,与驱动版本无关。

  2. 直接映射 BAR1 物理地址: 绕过 P2P API,直接对 BAR1 物理地址进行 ioremap_wc 映射。这也行不通,因为 GPU 的内部页表仅映射了约 16 MiB 的 BAR1 空间(仅用于显示帧缓冲区)。对其余部分的读取返回零。虽然 mkswap 看似成功,但 swapon 会失败,因为交换头实际上并不存在。

NBD 方案的优势nbd-vram 巧妙地避开了上述所有限制。cuMemcpyHtoDcuMemcpyDtoH 函数在任何支持 CUDA 的 GPU 上均可正常工作,无需特殊权限。此外,该方案无需编写或维护内核模块,不涉及 NVIDIA 内核符号,因此在内核和驱动更新后无需重新编译,具有极高的兼容性。

测试环境与性能表现

开发者在以下环境中进行了测试:

  • 硬件:RTX 3070 Laptop (GA104M),物理内存 16 GB,VRAM 8 GB。
  • 软件:驱动版本 580.159.03,内核 6.17,Pop!_OS。
  • 配置:分配 7 GB 用于交换。

内存溢出顺序(Overflow Order): 系统采用分层溢出策略以优化性能:

  1. RAM 填满:首先使用物理内存。
  2. VRAM 吸收溢出:当 RAM 不足时,数据溢出到 VRAM。由于通过 PCIe 传输,速度较快。
  3. zram 压缩:如果 VRAM 也满了,剩余数据由 CPU 进行压缩并存入 zram。
  4. SSD 交换:仅当上述所有资源耗尽时,才使用 SSD 交换。

性能数据: 在 RTX 3070 Laptop 上通过 test-fill.sh 进行的测试显示(7 GiB 顺序写入,4M 块):

  • 顺序吞吐量:约 1.3 GB/s。
  • 延迟:由于数据路径是通过 PCIe 到 GPU 而非存储设备,其延迟甚至低于 NVMe SSD。

最终结果(包括 zram 和 SSD 交换)使可寻址内存达到约 46 GB,是原始物理内存的三倍。

安装与配置

系统要求

  • 支持 CUDA 的 NVIDIA GPU(任何消费级 RTX/GTX 卡)。
  • 安装了 libcuda.so.1 的 NVIDIA 驱动(无需 CUDA Toolkit)。
  • Linux 内核 3.0+(大多数发行版已内置 nbd 模块)。
  • 软件包:nbd-client, gcc, make

安装步骤

git clone https://github.com/c0dejedi/nbd-vram
cd nbd-vram
sudo ./install.sh
sudo systemctl start vram-swap-nbd

验证安装: 运行 swapon --show,应能看到类似输出:

NAME       TYPE   SIZE USED PRIO
/dev/nbd0  partition 7G  0B  1500

配置调整

  • 显存大小:编辑 /etc/systemd/system/vram-swap-nbd.service,修改 VRAM_SETUP_SIZE_MB(例如 7168 表示 7 GB)。守护进程会尝试分配请求的大小,如果显存不足,会以 512 MiB 为步长回退,因此即使显示合成器已加载,它也能尽可能多地占用显存。
  • 优先级:修改 VRAM_SWAP_PRIORITY(数值越高,越优先使用)。建议将 VRAM 交换优先级设置得高于 SSD 交换,以便在 zram 之前吸收溢出。
  • 电源管理:安装时可选择启用电源感知管理。如果启用,当拔掉交流电源或电池低于阈值时,服务会自动停止;恢复供电后自动重启。

测试脚本

  • sudo bash test-nbd.sh:分配显存,连接 NBD 设备,执行 1 MiB 读写检查,激活交换,并打印卸载说明。
  • sudo bash test-fill.sh:在冒烟测试通过后,用零填充整个 VRAM 分区,验证样本读取,退出后自动恢复交换。

关键要点

  • 解决内存瓶颈:专为板载内存且无法升级的笔记本电脑设计,有效利用闲置的 GPU 显存作为交换空间。
  • 绕过驱动限制:通过 NBD 协议和 CUDA 内存拷贝 API,规避了 NVIDIA 驱动在消费级 GPU 上禁止直接物理内存访问(P2P)的限制。
  • 零内核模块依赖:无需编写或维护内核模块,不依赖 NVIDIA 内核符号,兼容性强,随内核/驱动更新无需重新编译。
  • 高性能溢出层:VRAM 交换速度(~1.3 GB/s)快于 SSD,且延迟更低,作为 RAM
查看原文 →github.com