Zswap Makes Swap Go Zoom
Linux kernel features zswap and zram both provide a compressed storage area in RAM for swap memory. But each takes a very different approach to achieve a fast(er) swap.
Start Here
The most apparent difference between the two approaches to swap management are that while zswap works in tandem with a swapfile or swap partition, zram does not require a backing swap device. So zram all the way, right? At least I thought so. I've used zram in the past to keep swap contents in speedy RAM vs not-as-speedy-storage, but after reading this comprehensive debunking of zswap and zram myths I've switched to zswap on my machines.
Different bootloaders initiate zswap differently. For the purposes of this HOWTO I profile two systems, each with a different bootloader: a Void Linux desktop using ZFSBootMenu (ZBM), and a Linux Mint Debian Edition (LMDE) laptop using GRUB. Both systems were provisioned with a swap partition during install.
To use zswap, I need to supply the desired arguments to the kernel at boot. These are the arguments I use:
zswap.enabled=1# the master switchzswap.compressor=lz4# prioritize the lowest latency vs a higher compression ratiozswap.zpool=zsmalloc# most modern and efficient memory allocatorzswap.max_pool_percent=10# zswap can use up to 10% of physical RAM
Configure the Bootloader
ZBM
If the system bootloader is ZBM, view the current boot arguments for (example) zroot/ROOT:
$ zfs get org.zfsbootmenu:commandline zroot/ROOT
NAME PROPERTY VALUE SOURCE
zroot/ROOT org.zfsbootmenu:commandline quiet hibernate=no local
NOTE
I had added the quiet and hiberate=no parameters earlier during the Void install.
Add the following boot arguments to ZBM:
sudo zfs set org.zfsbootmenu:commandline="quiet hiberate=no zswap.enabled=1 zswap.compressor=lz4 zswap.zpool=zsmalloc zswap.max_pool_percent=10" zroot/ROOT
Reboot the system.
GRUB
If the system bootloader is GRUB, view the current boot arguments by inspecting cmdline:
$ cat /proc/cmdline
BOOT_IMAGE=/boot/vmlinuz-6.12.95+deb13-amd64 root=UUID=<long_string_of_characters> ro quiet splash
Add the desired zswap boot arguments to GRUB by modifying the GRUB_CMDLINE_LINUX_DEFAULT setting, which exists in /etc/default/grub.
However, settings in this file can be overridden if additional config files exist in the /etc/default/grub.d directory. In LMDE this is indeed the case, which has a /etc/default/grub.d/50_lmde.cfg file. Higher numbered files in this directory are read later by GRUB in generating its config, and take precedence over earlier settings.
Since any changes made to 50_lmde.cfg may be lost in a future system upgrade, I create a custom file to hold the boot arguments:
echo 'GRUB_CMDLINE_LINUX_DEFAULT="quiet splash zswap.enabled=1 zswap.zpool=zsmalloc zswap.max_pool_percent=10"' | sudo tee /etc/default/grub.d/99_cmdline.cfg
NOTE
I've made a slight alteration here, dropping the zswap.compressor=lz4 argument. The reason is that on (all?) Debian-based distros like LMDE, the default lzo compressor is loaded very early in the boot process before the lz4 modules are considered (even if included in the initramfs) and the argument will fail. An alternative is described below in "Troubleshooting".
Update GRUB:
sudo update-grub
Reboot the system.
Verify
Cmdline
Arguments used to boot the system:
ZBM on Void
$ cat /proc/cmdline
root=zfs:zroot/ROOT/void quiet hiberate=no zswap.enabled=1 zswap.compressor=lz4 zswap.zpool=zsmalloc zswap.max_pool_percent=10 spl.spl_hostid=0x00bab10c
GRUB on LMDE
$ cat /proc/cmdline
BOOT_IMAGE=/boot/vmlinuz-6.12.95+deb13-amd64 root=UUID=<long_string_of_characters> ro quiet splash zswap.enabled=1 zswap.zpool=zsmalloc zswap.max_pool_percent=10Dmesg
Confirm zswap was loaded during boot:
Void
$ sudo dmesg | grep zswap
.
.
.
[ 0.507529] zswap: loaded using pool lz4
LMDE
$ sudo dmesg | grep zswap
.
.
.
[ 0.746379] zswap: loaded using pool lzo/zsmallocParameters
NOTE
On systems that are running more recent (6.18+) kernels (like Void) zsmalloc is now the exclusive backend for zswap, and the zpool option has been removed.
View live settings:
Void
$ grep -r . /sys/module/zswap/parameters/
/sys/module/zswap/parameters/enabled:Y
/sys/module/zswap/parameters/shrinker_enabled:N
/sys/module/zswap/parameters/max_pool_percent:10
/sys/module/zswap/parameters/compressor:lz4
/sys/module/zswap/parameters/accept_threshold_percent:90
LMDE
$ grep -r . /sys/module/zswap/parameters/
/sys/module/zswap/parameters/enabled:Y
/sys/module/zswap/parameters/shrinker_enabled:N
/sys/module/zswap/parameters/max_pool_percent:10
/sys/module/zswap/parameters/compressor:lzo
/sys/module/zswap/parameters/zpool:zsmalloc
/sys/module/zswap/parameters/accept_threshold_percent:90Statistics
View how zswap is performing:
sudo grep -r . /sys/kernel/debug/zswap/
If the above command outputs the error message:
grep: /sys/kernel/debug/zswap/: No such file or directory
...mount debugfs:
sudo mount -t debugfs none /sys/kernel/debug
...and re-run grep.
Troubleshooting
To use the zswap compressor of our choice on a system that won't accept it as a boot argument (i.e. lz4 on LMDE), one approach is to create a systemd service file that will switch compressors after zswap starts at boot.
Create zswap-compress.service:
sudo nano /etc/systemd/system/zswap-compress.service
Add:
[Unit]
Description=Configure zswap compressor to LZ4
After=systemd-modules-load.service
[Service]
Type=oneshot
ExecStart=/bin/bash -c 'echo lz4 > /sys/module/zswap/parameters/compressor'
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
Save changes and exit.
Enable the service:
sudo systemctl enable --now zswap-compress.service
Verify:
cat /sys/module/zswap/parameters/compressor
It should output lz4.
On the next reboot, dmesg may show a lz4 not available, using default log entry from the beginning of boot, but the systemd service will override it seconds later. After login, running the cat command above will output the current compressor handling the swap pool.
Resources
- Essential reading: Debunking zswap and zram myth
- Linux Kernel Admin Guide: zswap
- Arch Wiki: Zswap
You can like, share, or comment on this post on the Fediverse 💬
« Previous: Install Linux Mint Debian Edition (LMDE 7) in Expert Mode