254 lines
8.9 KiB
Bash
254 lines
8.9 KiB
Bash
#!/bin/bash
|
|
|
|
#This script enables ZRAM and attempts to optimize its effectiveness on Raspberry Pi computers.
|
|
#Useful links:
|
|
#https://haydenjames.io/linux-performance-almost-always-add-swap-part2-zram
|
|
#https://haydenjames.io/raspberry-pi-performance-add-zram-kernel-parameters/
|
|
#https://linuxreviews.org/Zram
|
|
#https://linuxize.com/post/how-to-change-the-swappiness-value-in-linux
|
|
|
|
#original zram script from novaspirit: https://github.com/novaspirit/rpi_zram
|
|
|
|
#define error, status and status_green functions in case this script is being run standalone without pi-apps api (wget -qO- https://raw.githubusercontent.com/Botspot/pi-apps/master/apps/More%20RAM/install | bash)
|
|
error() { #red text and exit 1
|
|
echo -e "\e[91m$1\e[0m" 1>&2
|
|
exit 1
|
|
}
|
|
status() { #cyan text to indicate what is happening
|
|
|
|
#detect if a flag was passed, and if so, pass it on to the echo command
|
|
if [[ "$1" == '-'* ]] && [ ! -z "$2" ];then
|
|
echo -e $1 "\e[96m$2\e[0m" 1>&2
|
|
else
|
|
echo -e "\e[96m$1\e[0m" 1>&2
|
|
fi
|
|
}
|
|
status_green() { #announce the success of a major action
|
|
echo -e "\e[92m$1\e[0m" 1>&2
|
|
}
|
|
|
|
set_value() { #Add the $1 line to the $2 config file. (setting=value format) This function changes the setting if it's already there.
|
|
local file="$2"
|
|
[ -z "$file" ] && error "set_value: path to config-file must be specified."
|
|
[ ! -f "$file" ] && error "Config file '$file' does not exist!"
|
|
local setting="$1"
|
|
|
|
#This function assumes a setting=value format. Remove the number value to be able to change it.
|
|
local setting_without_value="$(echo "$setting" | awk -F= '{print $1}')"
|
|
|
|
#edit the config file with the new value
|
|
sudo sed -i "s/^${setting_without_value}=.*/${setting}/g" "$file"
|
|
|
|
#ensure sed actually did something; if not, add setting to end of file
|
|
if ! grep -qxF "$setting" "$file" ;then
|
|
echo "$setting" | sudo tee -a "$file" >/dev/null
|
|
fi
|
|
}
|
|
|
|
set_sysctl_value() { #Change a setting for sysctl. Displays value, changes config file, and sets the value immediately.
|
|
set_value "$1" /etc/sysctl.conf
|
|
echo " - $1"
|
|
sudo sysctl "$1" >/dev/null
|
|
}
|
|
|
|
#disable dphys-swapfile service if running
|
|
if [ -f /usr/sbin/dphys-swapfile ] && systemctl is-active --quiet dphys-swapfile.service ;then
|
|
status "Disabling swap"
|
|
#swapoff and remove swapfile
|
|
sudo /usr/sbin/dphys-swapfile uninstall
|
|
|
|
#prevent dphys-swapfile from running on boot
|
|
sudo systemctl mask dphys-swapfile.service #see /lib/systemd/system/dphys-swapfile.service
|
|
fi
|
|
|
|
#Disable Ubuntu's mkswap service if running
|
|
if systemctl is-active --quiet mkswap.service ;then
|
|
status "Disabling swap"
|
|
#swapoff and remove swapfile
|
|
sudo systemctl disable mkswap.service
|
|
|
|
#prevent dphys-swapfile from running on boot
|
|
sudo systemctl mask mkswap.service
|
|
fi
|
|
|
|
PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
|
|
|
|
status -n "Checking system for compatibility... "
|
|
if [ "$(ps --no-headers -o comm 1)" != systemd ];then
|
|
error "\nUser error: Incompatible because your system was not booted with systemd."
|
|
elif ! command -v zramctl >/dev/null ;then
|
|
error "\nUser error: Incompatible because the 'zramctl' command is missing on your system."
|
|
elif ! command -v swapon >/dev/null ;then
|
|
error "\nUser error: Incompatible because the 'swapon' command is missing on your system."
|
|
elif ! command -v swapoff >/dev/null ;then
|
|
error "\nUser error: Incompatible because the 'swapoff' command is missing on your system."
|
|
elif ! command -v modprobe >/dev/null ;then
|
|
error "\nUser error: Incompatible because the 'modprobe' command is missing on your system."
|
|
fi
|
|
|
|
#load zram module
|
|
if command -v enable_module >/dev/null ;then
|
|
enable_module zram || exit 1
|
|
elif ! lsmod | awk '{print $1}' | grep -qxF zram ;then
|
|
if ! sudo modprobe zram &>/dev/null ;then
|
|
if [ ! -d "/lib/modules/$(uname -r)" ];then
|
|
error "\nUser error: Failed to load the 'zram' kernel module because you upgraded the kernel and have not rebooted yet.
|
|
Please reboot to load the new kernel, then try again."
|
|
else
|
|
error "\nUser error: Incompatible because the 'zram' kernel module is missing on your system."
|
|
fi
|
|
fi
|
|
fi
|
|
status_green "Done"
|
|
|
|
status "Creating zram script: /usr/bin/zram.sh"
|
|
echo '#!/bin/bash
|
|
|
|
export LANG=C
|
|
export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
|
|
|
|
if [ "$1" == --help ] || [ "$1" == -h ];then
|
|
echo -e "This is a script made by Botspot to increase usable RAM by setting up ZRAM.
|
|
ZRAM uses compression to fit more memory in your available RAM.
|
|
This script will setup a ZRAM swapspace that is 4 times larger than usable RAM.
|
|
It also configures high-speed RAM-based file-storage at /zram.
|
|
|
|
Usage:
|
|
|
|
sudo zram.sh Setup zram-swap and storage (if enabled)
|
|
sudo zram.sh stop Disable all ZRAM devices and exit
|
|
sudo zram.sh storage-off Disable the file-storage at /zram on next run
|
|
sudo zram.sh storage-on Enable the file-storage at /zram on next run
|
|
zram.sh --help, -h Display this information and exit"
|
|
exit 0
|
|
fi
|
|
|
|
|
|
if [ $(id -u) -ne 0 ]; then
|
|
echo "$0 must be run as root user"
|
|
exit 1
|
|
fi
|
|
|
|
#avoid creating /zram storage if storage-off flag passed
|
|
if [ "$1" == storage-off ]; then
|
|
#retain this flag for next boot
|
|
if ! grep -qxF "ExecStart=/usr/bin/zram.sh storage-off" /etc/systemd/system/zram-swap.service ;then
|
|
sed -i "s+^ExecStart=/usr/bin/zram.sh$+ExecStart=/usr/bin/zram.sh storage-off+g" /etc/systemd/system/zram-swap.service
|
|
fi
|
|
echo -e "zram.sh will not set up file-storage at /zram from now on."
|
|
#the /zram storage can be re-enabled with storage-on flag
|
|
elif [ "$1" == storage-on ]; then
|
|
sed -i "s+^ExecStart=/usr/bin/zram.sh storage-off$+ExecStart=/usr/bin/zram.sh+g" /etc/systemd/system/zram-swap.service
|
|
echo -e "zram.sh will set up file-storage at /zram from now on."
|
|
fi
|
|
|
|
# Load zram module
|
|
if ! lsmod | awk "{print $1}" | grep -qxF zram ;then
|
|
if ! modprobe zram ;then
|
|
echo "Failed to load zram kernel module"
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
# disable all zram devices
|
|
echo -n "Disabling zram... "
|
|
IFS=$'\''\n'\''
|
|
for device_number in $(find /dev/ -name zram* -type b | tr -cd "0123456789\n") ;do
|
|
#if zram device is a swap device, disable it
|
|
swapoff /dev/zram${device_number} 2>/dev/null
|
|
|
|
#if zram device is mounted, unmount it
|
|
umount /dev/zram${device_number} 2>/dev/null
|
|
|
|
#remove device
|
|
echo $device_number >/sys/class/zram-control/hot_remove
|
|
done
|
|
echo Done
|
|
|
|
rm -rf /zram
|
|
|
|
#exit script now if "exit" flag passed
|
|
if [ "$1" == stop ]; then
|
|
exit 0
|
|
fi
|
|
|
|
#create new zram drive - for swap
|
|
drive_num=$(cat /sys/class/zram-control/hot_add)
|
|
|
|
# use zstd compression if available - best option according to https://linuxreviews.org/Comparison_of_Compression_Algorithms#zram_block_drive_compression
|
|
if cat /sys/block/zram${drive_num}/comp_algorithm | grep -q zstd ;then
|
|
algorithm=zstd
|
|
else
|
|
algorithm=lz4
|
|
fi
|
|
echo $algorithm > /sys/block/zram${drive_num}/comp_algorithm
|
|
|
|
totalmem=$(free | grep -e "^Mem:" | awk '\''{print $2}'\'')
|
|
|
|
#create zram disk 4 times larger than usable RAM - compression ratio for zstd can approach 5:1 according to https://linuxreviews.org/Zram
|
|
echo $((totalmem * 1024 * 4)) > /sys/block/zram${drive_num}/disksize
|
|
|
|
#make the swap device (by default this will be /dev/zram0)
|
|
mkswap /dev/zram${drive_num}
|
|
swapon /dev/zram${drive_num} -d -p 1
|
|
|
|
#create second zram drive: for temporary user-storage at /zram
|
|
if ! grep -qxF "ExecStart=/usr/bin/zram.sh storage-off" /etc/systemd/system/zram-swap.service ;then
|
|
echo "Setting up ZRAM-powered file storage at /zram"
|
|
#create new zram drive
|
|
drive_num=$(cat /sys/class/zram-control/hot_add)
|
|
|
|
# set compression algorithm
|
|
echo $algorithm > /sys/block/zram${drive_num}/comp_algorithm
|
|
|
|
#set the size of drive to be 4 times the available RAM
|
|
echo $((totalmem * 1024 * 4)) > /sys/block/zram${drive_num}/disksize
|
|
|
|
#create a partition and mount it
|
|
mkfs.ext4 /dev/zram${drive_num} >/dev/null
|
|
mkdir -p /zram
|
|
mount /dev/zram${drive_num} /zram
|
|
chmod -R 777 /zram #make writable for any user
|
|
fi' | sudo tee /usr/bin/zram.sh >/dev/null
|
|
|
|
sudo chmod +x /usr/bin/zram.sh
|
|
|
|
status "Making it run on startup"
|
|
echo ' - Creating zram-swap.service'
|
|
echo '[Unit]
|
|
Description=Configures zram swap device
|
|
After=local-fs.target
|
|
|
|
[Service]
|
|
Type=oneshot
|
|
ExecStart=/usr/bin/zram.sh
|
|
ExecStop=/usr/bin/zram.sh stop
|
|
RemainAfterExit=yes
|
|
|
|
[Install]
|
|
WantedBy = multi-user.target' | sudo tee /etc/systemd/system/zram-swap.service >/dev/null
|
|
echo ' - Reloading Systemd unit files'
|
|
sudo systemctl daemon-reload
|
|
echo ' - Enabling zram-swap.service to run on boot'
|
|
sudo systemctl enable zram-swap.service
|
|
|
|
status -n "Running it now."
|
|
echo " Output:"
|
|
sudo /usr/bin/zram.sh || exit 1
|
|
|
|
status "Changing kernel parameters for better performance:"
|
|
#change kernel values as recommended by: https://haydenjames.io/linux-performance-almost-always-add-swap-part2-zram
|
|
set_sysctl_value vm.swappiness=100
|
|
set_sysctl_value vm.vfs_cache_pressure=500
|
|
set_sysctl_value vm.dirty_background_ratio=1
|
|
set_sysctl_value vm.dirty_ratio=50
|
|
|
|
echo
|
|
status_green "ZRAM should now be set up. Consider rebooting your device."
|
|
|
|
status "Below is a summary:"
|
|
zramctl
|
|
status "You can see this at any time by running 'zramctl'"
|
|
sleep 1
|
|
|