Blog/Zswap statistics

From Forza's ramblings

Swap/Virtual Memory[edit | edit source]

Opaque watercolor and gold on paper depicting a flying palace.
The Pushpaka Vimāna flying in the sky. Vimānas are mythological flying palaces or chariots described in Hindu texts and Sanskrit epics. The "Pushpaka Vimāna" of Ravana is a commonly most quoted example of a vimāna.

Swap memory is a feature that extends a computer's available memory by using a swap device (usually a hard disk or SSD) as a backup.

It moves inactive data from RAM to the swap space (known as swapping) , freeing up RAM for more important tasks. When needed, the data is retrieved from the swap space back into the system RAM. It prevents memory overload and allows the system to handle larger workloads.

While swap can free up RAM for critical tasks, it also makes access to data stored in swap space slower. This is because swap devices are much slower than system RAM.

Zswap[edit | edit source]

Linux zswap is a feature designed to improve the performance of systems with limited physical memory (RAM).

Instead of swapping data directly to the disk, zswap creates a compressed cache in RAM. When the system needs to swap data, zswap compresses the least recently used data and stores it in this cache. Since compression reduces the data size, zswap can fit more information in the available RAM. As a result, the system spends less time accessing the slower disk and can retrieve the compressed data faster from the cache. This compression and caching mechanism helps to improve overall system responsiveness and reduce disk I/O operations.

The benefits of zswap are twofold.

  • First, it allows your computer to make more efficient use of its available RAM. By compressing data before swapping it to disk, zswap effectively increases the amount of data that can be stored in RAM, reducing the need for disk access. This can lead to a smoother and more responsive user experience.
  • Second, zswap reduces wear on your storage device. Since swapping data to the disk can involve a significant number of read and write operations, utilizing zswap reduces the frequency of these operations, potentially extending the lifespan of your HDD or SSD.

Zswap tuning and statistics[edit | edit source]

Zswap is often enabled by default, and it can can be tuned using files in /sys/module/zswap/parameters. As of Kernel 6.3, the available options are as follows.

File Explanation
accept_threshold_percent Sets the accept threshold percentage for zswap.
compressor Specifies the compression algorithm used by zswap (options: lzo, lz4, zstd).
enabled Indicates whether zswap is enabled or disabled.
max_pool_percent Sets the maximum percentage of system memory that zswap can use for the compressed cache pool.
non_same_filled_pages_enabled Controls whether zswap compresses non-identical filled pages by checking their content.
same_filled_pages_enabled Controls whether zswap compresses identical filled pages by checking their content.
zpool Specifies the allocator used by zswap (options: zbud, z3fold, zsmalloc).

You can use grep . -R <path> to list all files and their current values. Here i pipe through sed to remove the path before the file names.

grep . -R /sys/module/zswap/parameters/ | sed 's|.*/||'
same_filled_pages_enabled:Y
enabled:Y
max_pool_percent:20
compressor:lz4
non_same_filled_pages_enabled:Y
zpool:zbud
accept_threshold_percent:90

In a similar way, it is possible to see some statistics on zswap. It requires that debugfs is mounted.

File Explanation
duplicate_entry Number of duplicate entries encountered during compression.
pool_limit_hit Number of times the pool limit was hit, resulting in rejected entries.
pool_total_size Total size of the compressed cache pool in bytes.
reject_alloc_fail Number of allocation failures during the compression process.
reject_compress_poor Number of times compression was skipped due to poor compression ratio.
reject_kmemcache_fail Number of failures while attempting to allocate memory from kernel memory caches.
reject_reclaim_fail Number of failures during the reclaim process to free up memory for compression.
same_filled_pages Number of pages compressed due to identical filled content.
stored_pages Number of pages currently stored in the compressed cache pool.
written_back_pages Number of pages written back from the compressed cache pool to swap space.

As before, we use grep to see the contents of each file.

grep . -R  /sys/kernel/debug/zswap/ | sed 's|.*/||' 
same_filled_pages:486839
stored_pages:1895764
pool_total_size:3092045824
duplicate_entry:0
written_back_pages:8
reject_compress_poor:652790
reject_kmemcache_fail:0
reject_alloc_fail:0
reject_reclaim_fail:0
pool_limit_hit:4

Shell script: zswap-stats[edit | edit source]

To make easier to interpret the statistics, I made a shell script to convert pages to bytes and summarize the result. The script can also be downloaded from https://mirrors.tnonline.net/

#!/bin/bash

# System page size
page_size=$(getconf PAGESIZE)

# Location of zswap settings
settings_dir="/sys/module/zswap/parameters"

# Location of zswap statistics
statistics_dir="/sys/kernel/debug/zswap"

# Array of zswap settings
settings=("accept_threshold_percent" "compressor" "enabled" "max_pool_percent" "non_same_filled_pages_enabled" "same_filled_pages_enabled" "zpool")

# Array of zswap statistics
statistics=("duplicate_entry" "pool_limit_hit" "pool_total_size" "reject_alloc_fail" "reject_compress_poor" "reject_kmemcache_fail" "reject_reclaim_fail" "same_filled_pages" "stored_pages")

# Declare an associative array to store zswap data
declare -A zswap_data

# Read zswap settings
for setting in "${settings[@]}"; do
	read -r value < "$settings_dir/$setting"
	zswap_data["$setting"]=$value
done

# Read zswap statistics
for stat in "${statistics[@]}"; do
	read -r value < "$statistics_dir/$stat"
	zswap_data["$stat"]=$value
done

# Determine the maximum length of keys (setting/statistic names)
max_length=0
for key in "${!zswap_data[@]}"; do
	if [ ${#key} -gt $max_length ]; then
		max_length=${#key}
	fi
done
((width = max_length + 4))

# Calculate the total size and compressed size in MiB
total_size=$((zswap_data["stored_pages"] * page_size / (1024 * 1024) ))
compressed_size=$((zswap_data["pool_total_size"] / (1024 * 1024) ))

# Calculate the compression ratio
if [ "${zswap_data["stored_pages"]}" -ne 0 ]; then
	compression_ratio=$(bc <<< "scale=2; (${zswap_data["stored_pages"]} * $page_size / ${zswap_data["pool_total_size"]})")
else
	compression_ratio=0
fi


# Output the zswap settings
printf "========\n"
printf "SETTINGS"
printf "\n========\n"
for key in "${settings[@]}"; do
    # Get the value from the associative array
    value=${zswap_data["$key"]}

    # Output the key (name) and value in columns
    printf "%-*s%s\n" "$width" "$key" "$value"
done

# Output the zswap data
printf "\n========\n"
printf "VALUES"
printf "\n========\n"
for key in "${statistics[@]}"; do
    # Get the value from the associative array
    value=${zswap_data["$key"]}

    # Output the key (name) and value in columns
    printf "%-*s%s\n" "$width" "$key" "$value"
done

# Output the total size, compressed size, and compression ratio
printf "\n========\n"
printf "SUMMARY"
printf "\n========\n"
printf "%-*s%s MiB\n" "$width" "Total Size:"        "$total_size"
printf "%-*s%s MiB\n" "$width" "Compressed Size:"   "$compressed_size"
printf "%-*s%s\n"     "$width" "Compression Ratio:" "$compression_ratio"

The results will look like this:

# zswap-stats
SETTINGS
accept_threshold_percent         90
compressor                       lz4
enabled                          Y
max_pool_percent                 20
non_same_filled_pages_enabled    Y
same_filled_pages_enabled        Y
zpool                            zbud

VALUES
duplicate_entry                  0
pool_limit_hit                   4
pool_total_size                  3014631424
reject_alloc_fail                0
reject_compress_poor             652790
reject_kmemcache_fail            0
reject_reclaim_fail              0
same_filled_pages                473882
stored_pages                     1811931

SUMMARY
Total Size:                      7077 MiB
Compressed Size:                 2874 MiB
Compression Ratio:               2.46