Zram

From LinuxReviews
Jump to navigationJump to search
Tux-000f.svg

zram is a Linux kernel module that allows you to create RAM-backed block devices with up to 5:1 compression. zram devices can be used like any other block device. They are typically used to make compressed swap devices using a machines RAM. They can also be used to store /tmp and anything else one might want to store on a compressed RAM-drive.

Fedora 33+ creates a zram swap device using half the systems memory, limited to a maximum of 4 GiB, using a tool called zram-generator.

Basic Usage[edit]

Howto-enable-a-zram-swap-device.jpg
Enabling a zram swap device in Cool-Retro-Term.

The zram module must be loaded to use zram. You can load it with modprobe zram if you want one zram block device or modprobe zram num_devices=4 if you want to create four zram devices when you initialize it. You can also set the number of devices by creating a file in /etc/modprobe.d/:

File: /etc/modprobe.d/zswap.conf
options zram num_devices=4

Creating Devices[edit]

zram devices are created as /dev/zram0, /dev/zram1 and so on. Additional drives can be created by simply reading /sys/class/zram-control/hot_add:

cat /sys/class/zram-control/hot_add

The compression algorithm can be changed by echoing to /sys/block/zram0/comp_algorithm. Reading that file with cat /sys/block/zram0/comp_algorithm outputs a list of supported algorithms you can use with the one in use in brackets. That list could look like lzo lzo-rle lz4 lz4hc 842 [zstd] or just [lzo] lzo-rle depending on where you got your kernel and who compiled it.

The trade-offs of various compression algorithms may not be what you think they are when you use zram. The module assumes that the compression ratio is about 2:1 and acts accordingly. Better compression will result in less actual allocated memory, and how fast the algorithm is will have an impact on performance. You will want to use zstd, lzo-rle or lzo in that order of preference (use the best one available in your kernel).

A zram drives size is 0 until you change that.

A zram devices size can be set by echoing a size to /sys/block/zram{devicenumber}/disksize. You can use multiples of bytes like K (or KiB), M and G:

echo 512M > /sys/block/zram0/disksize
echo 1G > /sys/block/zram1/disksize

zram does not use any actual memory before a device is filled with data. A 2 GiB drive with 5.8 MiB of data compressible down to 443.9K will use a total of 780K, not 2 GiB.

zram devices are initialized and ready to be used once a size is set. They will now be listed in /proc/partitions as if they were regular hard drives.

Turning a zram block device into a RAM-backed compressed swap is easy once the drive it initialized, it is merely a matter of running mkswap to make it a swap drive and swapon to enable that drive. Using the swapon argument -p 32767 will give a zram device the highest priority possible.

mkswap /dev/zram0
swapon /dev/zram0 -p 32767

Removing Devices[edit]

You can't just eradicate a zswap device while it is being used. You must first unmount any file system, or swap device, mounted on a zram device. Removing unused zram devices is a simple matter of echoing the device number to /sys/class/zram-control/hot_remove:

swapoff /dev/zram0
echo 0 > /sys/class/zram-control/hot_remove

Examining Devices[edit]

util-linux comes with a tool called zramctl which can be used to show a drives true compression ratio and other information. That information is also available in /sys/block/zram{devicenumber}/. You can do a close-up inspection of those files with

grep -H '' /sys/block/zram0/*

Simple Script For Using Zram As A Swap Device[edit]

You should use zram-generator (see below) to manage zram swap drives if you are using Fedora 33 or higher.

This simple script will create a zram swap device. Note that it assumes you are not using zram for anything else. It is not very elegant but it works just fine.

File: /usr/local/bin/zramswap-on
#!/bin/bash
# Disable zswap
echo 0 > /sys/module/zswap/parameters/enabled

# Load zram module
modprobe zram

# use zstd compression
echo zstd > /sys/block/zram0/comp_algorithm

# echo 512M > /sys/block/zram0/disksize
echo 2G > /sys/block/zram0/disksize

mkswap /dev/zram0

# Priority can have values between -1 and 32767
swapon /dev/zram0 -p 32767

This short simple script will remove the zram swap device. It, again, assumes that you are only using zram for compressed swap.

File: /usr/local/bin/zramswap-off
#!/bin/bash
swapoff /dev/zram0
echo 0 > /sys/class/zram-control/hot_remove
# Not required, but creating a blank uninitalzed drive
# after removing one may be desired
cat /sys/class/zram-control/hot_add

Remember to make the scripts executable with chmod +x.

This simple systemd unit file lets you have systemd start your zram swap drive at boot:

File: /etc/systemd/system/create-zram-swap.service
[Unit]
Description=Configures zram swap device
After=local-fs.target

[Service]
Type=oneshot
ExecStart=/usr/local/bin/zramswap-on
ExecStop=/usr/local/bin/zramswap-off
RemainAfterExit=yes

[Install]
WantedBy = multi-user.target

Create that service file, reload the service files with systemctl daemon-reload and you can enable and start it with

systemctl enable --now create-zram-swap.service

Compression Algorithms[edit]

Compiling Chromium-In-A-QEMU-VM-with-6GiB-3GiB-zram-zstd.jpg
Chromium 85 being compiled in a QEMU virtual machine with 6 GiB RAM and a 3 GiB zstd zram compressed swap.

Comparing how compression algorithms play out when they are used to store files on a a zram-backed regular file system in a repeatable fashion is easy. Here's how much RAM it takes to store the Linux kernel on a zram device:

Storing Linux 5.9 rc4
on a compressed zram block device
Algorithm cp time Data Compressed Total
lzo 4.571s 1.1G 387.8M 409.8M
lzo-rle 4.471s 1.1G 388M 410M
lz4 4.467s 1.1G 403.4M 426.4M
lz4hc 14.584s 1.1G 362.8M 383.2M
842 22.574s 1.1G 538.6M 570.5M
zstd 7.897s 1.1G 285.3M 298.8M

See Comparison of Compression Algorithms: zram block drive compression for details on how the above tests were done.

Comparing how the different compression algorithms play out when a zram block device is used as a swap device is a very different matter. This is how much memory is used when a 3 GiB zram swap is fully filled while building Chromium 85 in a virtual machine with just 6 GiB total system memory available (and a HDD backed swap):

Algorithm Disk size Data Compressed Total memory used
zstd 3G 3G 565.8M 599.4M
lzo-rle 3G 3G 811.1M 851M

The above real-world zram swap compression number with zstd indicate a 5:1 compression ratio while lzo-rle does something in the neighborhood of 3.7:1. This may or may not reflect what you get in your particular workload.

Performance Implications[edit]

Compiling Chromium with four threads on an old Athlon 5350 APU with a slow HDD as a swap device in addition to a zram swap device indicate that a small zram swap can have a negative impact while a larger zram swap has a positive impact. The slow old Athlon 5350 APU had two DDR3 1600 4 GiB sticks but only 7 GiB available due to 1 GiB being reserved by the APU.

Chromium 85 Compile times
Athlon 5350 APU, 8 (7) GiB RAM
RAM zram swap zswap (cache) compression time difference
7 GiB none none none 29h 9m (1748m48.292s) Baseline
7 GiB GiB none lzo-rle 29h 14m 1753m57.703s +5 minutes
7 GiB 1 GiB none zstd 30h 23m (1823m56.761s) +1 hours 15 minutes
7 GiB 2 GiB none zstd 28h 46m (1725m45.160s) -23 minutes
7 GiB 3.5 GiB
(50% of physical RAM)
none lzo-rle 27h 25m (1645m13.886s) -1 hour 44 minutes
7 GiB 3.5 GiB
(50% of physical RAM)
none zstd 27h 28m (1647m58.215s) -1 hour 41 minutes
7 GiB none 10% (700 MiB)
zbud
zstd 29h m4hm (1782m4.096s) + 33 minutes
7 GiB none 10% (700 MiB)
z3fold
zstd 30h 18m (1818m52.867s) +1 hour 10 minutes
7 GiB none 10% (700 MiB)
zsmalloc
zstd 28h 43m (1723m9.704s) -26 minutes
7 GiB none 20% (1400 MiB)
z3fold
zstd 30h 18m (1818m55.137s) +1 hour 10 minutes

The result are very different in a virtual machine with an artificial memory constraint. The performance impact is exact opposite of what it is in the real hardware test shown above: A larger zram swap device performs worse than a smaller one. This may be cause the non-zram swap device in the test below isn't entirely real: Host system caching is likely skewing the numbers below in ways that make a notable difference.

Chromium 85 Compile Times Under Memory Pressure
Ryzen 2600, 6 Cores/Threads (QEMU VM), 8 GiB RAM
Compiling Chromium requires a lot more than 8 GiB RAM. Compiling it with less causes a lot of swap activity making it an ideal test for zram and zswap efficiency.
RAM zram swap Compression Disk swap zswap cache Compile time Benefit
20G None 20G None 4h 30m (270m)
8G None 20G None 5h 33m (333m) Baseline
8G 4G None None FAIL (OOM)
8G 1G zstd 20G None 5h 26m (326m) -7m
8G 2G zstd 20G None 5h 19m (319m) -14m
8G 2G lzo-rle 20G None 5h 24m (324) -9m
8G 4G zstd 20G None 6h 21m (381m) +48m
8G 4G lzo-rle 20G None 6h 3m (363m) +30m
8G None zstd (z3fold) 20G 4% 5h 32m (332m) -1m
8G None zstd (z3fold) 20G 10% 6h (360m) +27m
Note how the enough RAM scenario is better than any combination of 8 GiB RAM and zram swap or zswap cahce.

Utilities[edit]

zramctl[edit]

zramctl, part of the util-linux package, can be used to setup and configure zram devices. Running zramctl with no arguments makes it output a list of zram devices and their status:

$ zramctl 
NAME       ALGORITHM DISKSIZE DATA COMPR TOTAL STREAMS MOUNTPOINT
/dev/zram1 zstd          512M   0B    0B    0B      12 
/dev/zram0 zstd            2G   4K   58B    4K      12 [SWAP]

zramctl has a -f or --find option that makes it either identify and use the first unused zram device or create a new zram device is no used devices are unavailable. That option can be used together with -s or --size and optionally -a or --algorithm to initialize a zram device:

zramctl --find --size 512M --algorithm zstd

zramctl will echo what device it played with when that command is executed. That would be /dev/zram0 if no devices are in use or /dev/zram2 if there are two existing zram devices present. That can be used as part of a script:

newdrive=`zramctl --find --size 512M --algorithm zstd`
echo ${newdrive}

See the zramctl.8 manpage for all the options. Note that the options the manual lists for --algorithm may not reflect what is available on your system, cat /sys/block/zram0/comp_algorithm to see what is actually available on your machine.

zram-generator[edit]

Fedora 33+ comes with, and by default, activates a tool called zram-generator (available from github.com /systemd/zram-generator).

zram-generator will, left unconfigured and ignored, create a zram swap device using half the systems memory but no more than 4 GiB in total (it will create a 2 GiB zram swap device if you have 4 GiB total, but only a 4 GiB zram swap device if you have 128 GiB of memory). It defaults to lzo-rle compression. That behavior is dictated by the package zram-generator-defaults which only contains a configuration file named /usr/lib/systemd/zram-generator.conf. You can override the default settings by creating a configuration file named /etc/systemd/zram-generator.conf:

File: /etc/systemd/zram-generator.conf
[zram0]
# Use 20% of system memory for zswap. Default: 0.5
zram-fraction = 0.2
# Limits the maximum size. Set in MiB. 2048 means
# it will never be larger than 2 GiB. Default: 4096
max-zram-size = 2048

# Fedora defaults to lzo-rle which is very inefficient
# compared to vastly superior zstd compression
compression-algorithm = zstd

zram-generator gained support for setting a swap priority on the zram swap devices it creates on January 13th, 2021. The default value, set by /src/config.rs, is 100.

File: /etc/systemd/zram-generator.conf
swap-priority=32767

The swap-priority= setting, available in v0.3.0-rc.1 and newer, is likely something you want if you have existing swap devices. A pretty typical disk swap priority of 5000 or 10000 (the range is >-1 to 32767 where 32767 has highest priority) will make Linux swap to disk before it swaps to the RAM-backed swap device if the foolish in-practice lowest-priority zram-generator default of just 100 is used.

zram-generator can be disabled using any of three different methods:

  1. mask it by running systemctl mask swap-create@.service (that's the actual service you need to mask, it is not named zram-generator)
  2. create a _blank_ configuration file (echo > /etc/systemd/zram-generator.conf)
  3. eradicate the zram-generator and zram-generator-defaults packages (dnf -y remove zram-generator zram-generator-defaults).

A zram swap is a good addition to a regular swap device as long as the drives size is less than 25% of total system memory so you may want to configure it correctly instead of disabling it if you are unhappy with the silly Fedora 33 defaults.

zram and zswap[edit]

The Linux kernel has a similarly-sounding kernel module called zswap. It is easy to confuse a zram swap with a zswap since it sounds similar. However, they are not the same thing.

zswap is fundamentally different in one simple way: It is a swap drive cache. It can compress pages going to a swap device in RAM and compress up to 3:1 if you use zstd compression and the z3fold zpool.

Pick one or the other, don't use both. Using a compressed memory cache to cache a compressed memory block device is foolish unless you have some very unusual and very specific requirements. Using it to cache a hard disk swap does make sense. You can not configure zswap to only cache a specific swap device so it does not sense to use it even if your machine has a real swap if you also use a zram swap.

See Also[edit]

  • zswap can be used to create a up to 3:1 memory compressed swap cache.


Add your comment
LinuxReviews welcomes all comments. If you do not want to be anonymous, register or log in. It is free.