knowledge/technology/linux/Zram.md
2024-12-20 12:46:21 +01:00

11 KiB

obj arch-wiki source wiki rev
concept https://wiki.archlinux.org/title/Zram https://docs.kernel.org/admin-guide/blockdev/zram.html https://en.wikipedia.org/wiki/Zram 2024-12-20

Zram

zram, formerly called compcache, is a Linux kernel module for creating a compressed block device in RAM, i.e. a RAM disk with on-the-fly disk compression. The block device created with zram can then be used for swap or as a general-purpose RAM disk. The two most common uses for zram are for the storage of temporary files (/tmp) and as a swap device. Initially, zram had only the latter function, hence the original name "compcache" ("compressed cache").

Usage as swap

Initially the created zram block device does not reserve or use any RAM. Only as files need or want to be swapped out, they will be compressed and moved into the zram block device. The zram block device will then dynamically grow or shrink as required.

Even when assuming that zstd only achieves a conservative 1:2 compression ratio (real world data shows a common ratio of 1:3), zram will offer the advantage of being able to store more content in RAM than without memory compression.

Manually

To set up one zstd compressed zram device with half the system memory capacity and a higher-than-normal priority (only for the current session):

modprobe zram
zramctl /dev/zram0 --algorithm zstd --size "$(($(grep -Po 'MemTotal:\s*\K\d+' /proc/meminfo)/2))KiB"
mkswap -U clear /dev/zram0
swapon --discard --priority 100 /dev/zram0

To disable it again, either reboot or run:

swapoff /dev/zram0
modprobe -r zram
echo 1 > /sys/module/zswap/parameters/enabled

For a permanent solution, use a method from one of the following sections.

Using a udev rule

The example below describes how to set up swap on zram automatically at boot with a single udev rule. No extra package should be needed to make this work.

Explicitly load the module at boot:

# /etc/modules-load.d/zram.conf
zram

Create the following udev rule adjusting the disksize attribute as necessary:

# /etc/udev/rules.d/99-zram.rules
ACTION=="add", KERNEL=="zram0", ATTR{comp_algorithm}="zstd", ATTR{disksize}="4G", RUN="/usr/bin/mkswap -U clear /dev/%k", TAG+="systemd"

Add /dev/zram to your fstab with a higher than default priority:

# /etc/fstab
/dev/zram0 none swap defaults,discard,pri=100 0 0

Using zram-generator

zram-generator provides systemd-zram-setup@zramN.service units to automatically initialize zram devices without users needing to enable/start the template or its instances.

To use it, install zram-generator, and create /etc/systemd/zram-generator.conf with the following:

# /etc/systemd/zram-generator.conf

[zram0]
zram-size = min(ram / 2, 4096)
compression-algorithm = zstd

zram-size is the size (in MiB) of zram device, you can use ram to represent the total memory.

compression-algorithm specifies the algorithm used to compress in zram device.
cat /sys/block/zram0/comp_algorithm gives the available compression algorithm (as well as the current one included in brackets).

Then run daemon-reload, start your configured systemd-zram-setup@zramN.service instance (N matching the numerical instance-ID, in the example it is systemd-zram-setup@zram0.service).

You can check the swap status of your configured /dev/zramN device(s) by reading the unit status of your systemd-zram-setup@zramN.service instance(s), by using zramctl, or by using swapon.

zramctl

zramctl is used to quickly set up zram device parameters, to reset zram devices, and to query the status of used zram devices.

Usage:

# Get info:
# If no option is given, all non-zero size zram devices are shown.
zramctl [options]

# Reset zram:
zramctl -r zramdev...

# Print name of first unused zram device:
zramctl -f

# Set up a zram device:
zramctl [-f | zramdev] [-s size] [-t number] [-a algorithm]

Options

Option Description
-a, --algorithm lzo/lz4/lz4hc/deflate/842/zstd Set the compression algorithm to be used for compressing data in the zram device. The list of supported algorithms could be inaccurate as it depends on the current kernel configuration. A basic overview can be obtained by using the command cat /sys/block/zram0/comp_algorithm;
-f, --find Find the first unused zram device. If a --size argument is present, then initialize the device.
-n, --noheadings Do not print a header line in status output. `
-o, --output list Define the status output columns to be used. If no output arrangement is specified, then a default set is used. See below for list of all supported columns.
--output-all Output all available columns.
--raw Use the raw format for status output.
-r, --reset Reset the options of the specified zram device(s). Zram device settings can be changed only after a reset.
-s, --size size Create a zram device of the specified size. Zram devices are aligned to memory pages; when the requested size is not a multiple of the page size, it will be rounded up to the next multiple. When not otherwise specified, the unit of the size parameter is bytes.
-t, --streams number Set the maximum number of compression streams that can be used for the device. The default is use all CPUs and one stream for kernels older than 4.6.

Output Columns

Output Description
NAME zram device name
DISKSIZE limit on the uncompressed amount of data
DATA uncompressed size of stored data
COMPR compressed size of stored data
ALGORITHM the selected compression algorithm
STREAMS number of concurrent compress operations
ZERO-PAGES empty pages with no allocated memory
TOTAL all memory including allocator fragmentation and metadata overhead
MEM-LIMIT memory limit used to store compressed data
MEM-USED memory zram has consumed to store compressed data
MIGRATED number of objects migrated by compaction
COMP-RATIO compression ratio: DATA/TOTAL
MOUNTPOINT where the device is mounted

Misc

Checking zram statistics

Use zramctl. Example:

$ zramctl

NAME       ALGORITHM DISKSIZE  DATA  COMPR  TOTAL STREAMS MOUNTPOINT
/dev/zram0 zstd           32G  1.9G 318.6M 424.9M      16 [SWAP]

    DISKSIZE = 32G: this zram device will store up to 32 GiB of uncompressed data.
    DATA = 1.9G: currently, 1.9 GiB (uncompressed) of data is being stored in this zram device
    COMPR = 318.6M: the 1.9 GiB uncompressed data was compressed to 318.6 MiB
    TOTAL = 424.9M: including metadata, the 1.9 GiB of uncompressed data is using up 424.9 MiB of physical RAM

Multiple zram devices

By default, loading the zram module creates a single /dev/zram0 device.

If you need more than one /dev/zram device, specify the amount using the num_devices kernel module parameter or add them as needed afterwards.

Optimizing swap on zram

Since zram behaves differently than disk swap, we can configure the system's swap to take full potential of the zram advantages:

# /etc/sysctl.d/99-vm-zram-parameters.conf

vm.swappiness = 180
vm.watermark_boost_factor = 0
vm.watermark_scale_factor = 125
vm.page-cluster = 0

Enabling a backing device for a zram block

zram can be configured to push incompressible pages to a specified block device when under memory pressure.

To add a backing device manually:

echo /dev/sdX > /sys/block/zram0/backing_dev

To add a backing device to your zram block device using zram-generator, update /etc/systemd/zram-generator.conf with the following under your [zramX] device you want the backing device added to:

# /etc/systemd/zram-generator.conf

writeback-device=/dev/disk/by-partuuid/XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX

Using zram for non-swap purposes

zram can also be used as a generic RAM-backed block device, e.g. a /dev/ram with less physical memory usage, but slightly lower performance. However there are some caveats:

  • There is no partition table support (no automatic creation of /dev/zramxpy).
  • The block size is fixed to 4 kiB.

The obvious way around this is to stack a loop device on-top the zram, using losetup, specifying the desired block size using the -b option and the -P option to process partition tables and automatic creation of the partition loop devices.

zramctl -f -s <SIZE>G

Copy the disk image to the new /dev/zramx, then create a loop device. If the disk image has a partition table, the block size of the loop device must match the block size used by the partition table, which is typically 512 or 4096 bytes.

losetup -f -b 512 -P /dev/zramx

mount /dev/loop0p1 /mnt/boot
mount /dev/loop0p2 /mnt/root