Skip to content

Instantly share code, notes, and snippets.

@senhan07
Created December 6, 2022 09:01
Show Gist options
  • Save senhan07/bff16be0edbb7e55cfd9ef2181e32613 to your computer and use it in GitHub Desktop.
Save senhan07/bff16be0edbb7e55cfd9ef2181e32613 to your computer and use it in GitHub Desktop.
More RAM for Raspberry Pi
#!/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."
elif ! sudo modprobe zram &>/dev/null ;then
error "\nUser error: Incompatible because the 'zram' kernel module is missing on your system."
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 ! modprobe zram ;then
echo "Failed to load zram kernel module"
exit 1
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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment