Blog/Zswap statistics
Swap/Virtual Memory[edit | edit source]
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