在显存上进行交换

来自 ArchWiki
(重定向自 Swap on video ram)

在极少数情况下,如果您拥有极少的 RAM 和大量的显存,您可以将后者用作交换空间。

MTD 内核子系统

潜在优势

使用内核的 MTD 子系统,可以将配备 GDDRX SDRAM 或 DDR SDRAM 的显卡用作交换空间。拥有 256 MB 或以上独立显存且系统内存(DDRX SDRAM)有限的系统可能从这种设置中获益最多。

警告
  • 这不适用于闭源驱动程序。
  • 除非您的显卡驱动程序可以设置为使用比检测到的显存更少的内存,否则当您尝试使用同一部分 RAM 来存储纹理和交换空间时,Xorg 可能会崩溃。使用允许您覆盖显存设置的视频驱动程序应该可以提高稳定性。

预先设置

您必须加载模块,指定与您的显卡上的 RAM 相对应的 PCI 地址范围。

要查找可用的内存范围,请运行以下命令并查找 VGA 兼容控制器部分(请参见下面的示例)。

$ lspci -vvv
01:00.0 VGA compatible controller: NVIDIA Corporation GK104 [GeForce GTX 670] (rev a1) (prog-if 00 [VGA controller])
	Subsystem: ASUSTeK Computer Inc. Device 8405
	Control: I/O+ Mem+ BusMaster+ SpecCycle- MemWINV- VGASnoop- ParErr- Stepping- SERR- FastB2B- DisINTx-
	Status: Cap+ 66MHz- UDF- FastB2B- ParErr- DEVSEL=fast >TAbort- <TAbort- <MAbort- >SERR- <PERR- INTx-
	Latency: 0
	Interrupt: pin A routed to IRQ 57
	Region 0: Memory at f5000000 (32-bit, non-prefetchable) [size=16M]
	Region 1: Memory at e8000000 (64-bit, prefetchable) [size=128M]
	Region 3: Memory at f0000000 (64-bit, prefetchable) [size=32M]
	Region 5: I/O ports at e000 [size=128]
	[virtual] Expansion ROM at f6000000 [disabled] [size=512K]
	Capabilities: <access denied>
	Kernel driver in use: nvidia
	Kernel modules: nouveau, nvidia
注意: 具有多个 GPU 的系统可能会在此处有多个条目。

最有可能受益的区域是可预取的、64 位的且尺寸最大的区域。

注意: 上面使用的显卡具有 2 GB 的 GDDR5 SDRAM,但如上所示,命令提供的输出并未显示或列出全部容量。

显卡需要一些内存才能正常工作,因此需要进行一些计算。偏移量很容易以 2 的幂次方计算。显卡应使用地址范围的开头部分作为帧缓冲区,用于纹理等。但是,如果有限制,或者如本文开头所述,如果两个程序尝试写入相同的扇区,则可能会出现稳定性问题。

例如:对于总共 256 MB 的显存,公式为 2^28(2 的 28 次方)。大约 64 MB 可以留给显存,因此显存交换空间的使用起始范围将使用公式 2^26 计算。

使用上面的数字,您可以取差值并确定一个合理的范围用作交换内存。为正常功能留下 2^24 (32M)(更少也可以正常工作)

设置

配置 phram 模块(3.x 内核使用 slram 模块)

/etc/modprobe.d/modprobe.conf
options phram phram=VRAM,0xStartRange,0xUsedAmount

在启动时加载模块

/etc/modules-load.d/vramswap.conf
phram
mtdblock

创建一个 systemd 服务

/usr/lib/systemd/system/vramswap.service
[Unit]
Description=Swap on Video RAM

[Service]
Type=oneshot
ExecStart=/usr/bin/mkswap /dev/mtdblock0
ExecStart=/usr/bin/swapon /dev/mtdblock0 -p 10
ExecStop=/usr/bin/swapoff /dev/mtdblock0
RemainAfterExit=yes

[Install]
WantedBy=multi-user.target
提示: 如果您的计算机有多个 mtdblock 设备,请使用 cat /proc/mtd 查找名称为 VRAM 的 mtdblock

Xorg 驱动配置

为了保持 X 的稳定性,需要告知您的视频驱动程序使用少于检测到的显存。

/etc/X11/xorg.conf.d/vramswap.conf
Section "Device"
    Driver "radeon" # or whichever other driver you use
    VideoRam 32768
	#other stuff
EndSection

上面的示例指定您使用 32 MB 的显存。

注意: 某些驱动程序可能会将显存大小的数字视为 MiB。请参阅相关的手册页。

故障排除

以下命令可能有助于您获取不同空间(如磁盘分区、闪存盘)以及可能在本例中显存交换空间中已使用的交换空间。

swapon -s

参见

FUSE 文件系统

警告: 多位用户报告称,即使使用了 #Complete_system_freeze_under_high_memory_pressure 中的修复程序,这仍会导致系统 冻结。其他 GPU 管理进程或库可能会被交换出去,从而导致无法恢复的页面错误。

此方法适用于支持 OpenCL 的硬件,使用 FUSE 文件系统作为交换文件的后端。有关更多信息,请参阅 GPGPU

设置

首先,安装 vramfs-gitAUR。然后,创建一个空目录作为挂载点(例如 /tmp/vram)。

现在运行以下命令以设置 vramfs 和交换文件。

# vramfs /tmp/vram 256MB -f # Substitute 256M with your target vramfs size
# mkswap -U clear --size 200M --file /tmp/vram/swapfile # Substitute 200 with your target swapspace size in MiB

您的交换空间现在应该已准备就绪。运行 swapon 进行检查。

有关更多信息,请参阅 Swap#交换文件

注意: 这不是持久性的,系统重启后将会消失。
提示: 您也可以将 /tmp/vram 用作临时存储,很像 Tmpfs

设置 swappiness

注意: 以下建议可能不适用于您的用例。您应始终进行必要的尽职调查,并检查它如何应用于您的特定配置。

在显存上进行交换的情况下,增加 swappiness 可能是个好主意。当 VRAM 交换文件的随机 I/O 速度明显快于随机磁盘 I/O 时,情况尤其如此,因为缓存磁盘读取的好处将超过交换的成本。例如,如果您的随机磁盘 I/O 速度与 VRAM 交换 I/O 速度相同,则应将 swappiness 设置为 100。如果 VRAM 交换 I/O 速度比磁盘 I/O 速度快 2 倍,则应将 swappiness 设置为 133。有关如何正确计算 swappiness 值的更多信息,请参阅内核文档

故障排除

swapon: /tmp/vram/swapfile: 跳过 - 它似乎有空洞。

创建的交换文件不是连续的。可以设置环回设备来解决此问题。

# cd /tmp/vram
# LOOPDEV=$(losetup -f)
# truncate -s 4G swapfile # replace 4G with target swapspace size, has to be smaller than the allocated vramfs
# losetup $LOOPDEV swapfile
# mkswap $LOOPDEV
# swapon $LOOPDEV

高内存压力下系统完全冻结

有时,在极高的内存压力下,vramfs 进程本身可能会被交换到显存交换空间。这会导致完全死锁。一种解决方法是通过 cgroups 使该进程不可交换,方法是通过 systemd 文件启动它

/etc/systemd/system/vramswap.service
[Unit]
Description=Set up swap in VRAM
After=default.target

[Service]
Type=oneshot
RemainAfterExit=yes
# Change /root/vramswap.sh to a path to a script that performs all the necessary setup
ExecStart=/root/vramswap.sh
TimeoutStartSec=0
# Prevent swapping
MemorySwapMax=0

[Install]
WantedBy=default.target

参见