Without the redirect to /dev/null, an error message would be reported in TuneD logs on aarch64 machines, which do not have the kernel module. Resolves: RHEL-79943
591 lines
13 KiB
Text
591 lines
13 KiB
Text
#
|
|
# This is library of helper functions that can be used in scripts in tuned profiles.
|
|
#
|
|
# API provided by this library is under heavy development and could be changed anytime
|
|
#
|
|
|
|
#
|
|
# Config
|
|
#
|
|
STORAGE=/run/tuned
|
|
STORAGE_PERSISTENT=/var/lib/tuned
|
|
STORAGE_SUFFIX=".save"
|
|
|
|
#
|
|
# Helpers
|
|
#
|
|
|
|
# Save value
|
|
# $0 STORAGE_NAME VALUE
|
|
save_value() {
|
|
[ "$#" -ne 2 ] && return
|
|
[ "$2" -a -e "${STORAGE}" ] && echo "$2" > "${STORAGE}/${1}${STORAGE_SUFFIX}"
|
|
}
|
|
|
|
# Parse sysfs value, i.e. for "val1 [val2] val3" return "val2"
|
|
# $0 SYSFS_NAME
|
|
parse_sys() {
|
|
local V1 V2
|
|
[ -r "$1" ] || return
|
|
V1=`cat "$1"`
|
|
V2="${V1##*[}"
|
|
V2="${V2%%]*}"
|
|
echo "${V2:-$V1}"
|
|
}
|
|
|
|
# Save sysfs value
|
|
# $0 STORAGE_NAME SYSFS_NAME
|
|
save_sys() {
|
|
[ "$#" -ne 2 ] && return
|
|
[ -r "$2" -a ! -e "${STORAGE}/${1}${STORAGE_SUFFIX}" ] && parse_sys "$2" > "${STORAGE}/${1}${STORAGE_SUFFIX}"
|
|
}
|
|
|
|
# Set sysfs value
|
|
# $0 SYSFS_NAME VALUE
|
|
set_sys() {
|
|
[ "$#" -ne 2 ] && return
|
|
[ -w "$1" ] && echo "$2" > "$1"
|
|
}
|
|
|
|
# Save and set sysfs value
|
|
# $0 STORAGE_NAME SYSFS_NAME VALUE
|
|
save_set_sys() {
|
|
[ "$#" -ne 3 ] && return
|
|
save_sys "$1" "$2"
|
|
set_sys "$2" "$3"
|
|
}
|
|
|
|
# Get stored sysfs value from storage
|
|
# $0 STORAGE_NAME
|
|
get_stored_sys() {
|
|
[ "$#" -ne 1 ] && return
|
|
[ -r "${STORAGE}/${1}${STORAGE_SUFFIX}" ] && cat "${STORAGE}/${1}${STORAGE_SUFFIX}"
|
|
}
|
|
|
|
# Restore value from storage
|
|
# $0 STORAGE_NAME
|
|
restore_value() {
|
|
[ "$#" -ne 1 ] && return
|
|
_rs_value="`get_stored_sys \"$1\"`"
|
|
unlink "${STORAGE}/${1}${STORAGE_SUFFIX}" >/dev/null 2>&1
|
|
[ "$_rs_value" ] && echo "$_rs_value"
|
|
}
|
|
|
|
# Restore sysfs value from storage, if nothing is stored, use VALUE
|
|
# $0 STORAGE_NAME SYSFS_NAME [VALUE]
|
|
restore_sys() {
|
|
[ "$#" -lt 2 -o "$#" -gt 3 ] && return
|
|
_rs_value="`get_stored_sys \"$1\"`"
|
|
unlink "${STORAGE}/${1}${STORAGE_SUFFIX}" >/dev/null 2>&1
|
|
[ "$_rs_value" ] || _rs_value="$3"
|
|
[ "$_rs_value" ] && set_sys "$2" "$_rs_value"
|
|
}
|
|
|
|
|
|
#
|
|
# DISK tuning
|
|
#
|
|
|
|
DISKS_DEV="$(command ls -d1 /dev/[shv]d*[a-z] 2>/dev/null)"
|
|
DISKS_SYS="$(command ls -d1 /sys/block/{sd,cciss,dm-,vd,dasd,xvd}* 2>/dev/null)"
|
|
|
|
_check_elevator_override()
|
|
{
|
|
/bin/fgrep -q 'elevator=' /proc/cmdline
|
|
}
|
|
|
|
# $0 OPERATOR DEVICES ELEVATOR
|
|
_set_elevator_helper() {
|
|
_check_elevator_override && return
|
|
SYS_BLOCK_SDX=""
|
|
[ "$2" ] && SYS_BLOCK_SDX=$(eval LANG=C /bin/ls -1 "${2}" 2>/dev/null)
|
|
|
|
# if there is no kernel command line elevator settings, apply the elevator
|
|
if [ "$1" -a "$SYS_BLOCK_SDX" ]; then
|
|
for i in $SYS_BLOCK_SDX; do
|
|
se_dev="`echo \"$i\" | sed 's|/sys/block/\([^/]\+\)/queue/scheduler|\1|'`"
|
|
$1 "elevator_${se_dev}" "$i" "$3"
|
|
done
|
|
fi
|
|
}
|
|
|
|
# $0 DEVICES ELEVATOR
|
|
set_elevator() {
|
|
_set_elevator_helper save_set_sys "$1" "$2"
|
|
}
|
|
|
|
# $0 DEVICES [ELEVATOR]
|
|
restore_elevator() {
|
|
re_elevator="$2"
|
|
[ "$re_elevator" ] || re_elevator=cfq
|
|
_set_elevator_helper restore_sys "$1" "$re_elevator"
|
|
}
|
|
|
|
# SATA Aggressive Link Power Management
|
|
# usage: set_disk_alpm policy
|
|
set_disk_alpm() {
|
|
policy=$1
|
|
|
|
for host in /sys/class/scsi_host/*; do
|
|
if [ -f $host/ahci_port_cmd ]; then
|
|
port_cmd=`cat $host/ahci_port_cmd`;
|
|
if [ $((0x$port_cmd & 0x240000)) = 0 -a -f $host/link_power_management_policy ]; then
|
|
echo $policy >$host/link_power_management_policy;
|
|
else
|
|
echo "max_performance" >$host/link_power_management_policy;
|
|
fi
|
|
fi
|
|
done
|
|
}
|
|
|
|
# usage: set_disk_apm level
|
|
set_disk_apm() {
|
|
level=$1
|
|
for disk in $DISKS_DEV; do
|
|
hdparm -B $level $disk &>/dev/null
|
|
done
|
|
}
|
|
|
|
# usage: set_disk_spindown level
|
|
set_disk_spindown() {
|
|
level=$1
|
|
for disk in $DISKS_DEV; do
|
|
hdparm -S $level $disk &>/dev/null
|
|
done
|
|
}
|
|
|
|
# usage: multiply_disk_readahead by
|
|
multiply_disk_readahead() {
|
|
by=$1
|
|
|
|
# float multiplication not supported in bash
|
|
# bc might not be installed, python is available for sure
|
|
|
|
for disk in $DISKS_SYS; do
|
|
control="${disk}/queue/read_ahead_kb"
|
|
old=$(cat $control)
|
|
new=$(echo "print int($old*$by)" | python)
|
|
|
|
(echo $new > $control) &>/dev/null
|
|
done
|
|
}
|
|
|
|
# usage: remount_disk options partition1 partition2 ...
|
|
remount_partitions() {
|
|
options=$1
|
|
shift
|
|
|
|
for partition in $@; do
|
|
mount -o remount,$options $partition >/dev/null 2>&1
|
|
done
|
|
}
|
|
|
|
remount_all_no_rootboot_partitions() {
|
|
[ "$1" ] || return
|
|
# Find non-root and non-boot partitions, disable barriers on them
|
|
rootvol=$(df -h / | grep "^/dev" | awk '{print $1}')
|
|
bootvol=$(df -h /boot | grep "^/dev" | awk '{print $1}')
|
|
volumes=$(df -hl --exclude=tmpfs | grep "^/dev" | awk '{print $1}')
|
|
nobarriervols=$(echo "$volumes" | grep -v $rootvol | grep -v $bootvol)
|
|
remount_partitions "$1" $nobarriervols
|
|
}
|
|
|
|
|
|
DISK_QUANTUM_SAVE="${STORAGE}/disk_quantum${STORAGE_SUFFIX}"
|
|
|
|
set_disk_scheduler_quantum() {
|
|
value=$1
|
|
rm -f "$DISK_QUANTUM_SAVE"
|
|
for disk in $DISKS_SYS; do
|
|
control="${disk}/queue/iosched/quantum"
|
|
echo "echo $(cat $control) > $control" >> "$DISK_QUANTUM_SAVE" 2>/dev/null
|
|
(echo $value > $control) &2>/dev/null
|
|
done
|
|
}
|
|
|
|
restore_disk_scheduler_quantum() {
|
|
if [ -r "$DISK_QUANTUM_SAVE" ]; then
|
|
/bin/bash "$DISK_QUANTUM_SAVE" &>/dev/null
|
|
rm -f "$DISK_QUANTUM_SAVE"
|
|
fi
|
|
}
|
|
|
|
#
|
|
# CPU tuning
|
|
#
|
|
|
|
CPUSPEED_ORIG_GOV="${STORAGE}/cpuspeed-governor-%s${STORAGE_SUFFIX}"
|
|
CPUS="$(ls -d1 /sys/devices/system/cpu/cpu* | sed 's;^.*/;;' | grep "cpu[0-9]\+")"
|
|
|
|
# set CPU governor setting and store the old settings
|
|
# usage: set_cpu_governor governor
|
|
set_cpu_governor() {
|
|
governor=$1
|
|
|
|
# direct change using sysfs
|
|
if [ -e /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor ]; then
|
|
|
|
for cpu in $CPUS; do
|
|
gov_file=/sys/devices/system/cpu/$cpu/cpufreq/scaling_governor
|
|
save_file=$(printf $CPUSPEED_ORIG_GOV $cpu)
|
|
rm -f $save_file
|
|
if [ -e $gov_file ]; then
|
|
cat $gov_file > $save_file
|
|
echo $governor > $gov_file
|
|
fi
|
|
done
|
|
fi
|
|
}
|
|
|
|
# re-enable previous CPU governor settings
|
|
# usage: restore_cpu_governor
|
|
restore_cpu_governor() {
|
|
if [ -e /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor ]; then
|
|
for cpu in $CPUS; do
|
|
cpufreq_dir=/sys/devices/system/cpu/$cpu/cpufreq
|
|
save_file=$(printf $CPUSPEED_ORIG_GOV $cpu)
|
|
|
|
if [ -e $cpufreq_dir/scaling_governor ]; then
|
|
if [ -e $save_file ]; then
|
|
cat $save_file > $cpufreq_dir/scaling_governor
|
|
rm -f $save_file
|
|
else
|
|
echo userspace > $cpufreq_dir/scaling_governor
|
|
cat $cpufreq_dir/cpuinfo_max_freq > $cpufreq_dir/scaling_setspeed
|
|
fi
|
|
fi
|
|
done
|
|
fi
|
|
}
|
|
|
|
_cpu_multicore_powersave() {
|
|
value=$1
|
|
[ -e /sys/devices/system/cpu/sched_mc_power_savings ] && echo $value > /sys/devices/system/cpu/sched_mc_power_savings
|
|
}
|
|
|
|
# enable multi core power savings for low wakeup systems
|
|
enable_cpu_multicore_powersave() {
|
|
_cpu_multicore_powersave 1
|
|
}
|
|
|
|
disable_cpu_multicore_powersave() {
|
|
_cpu_multicore_powersave 0
|
|
}
|
|
|
|
#
|
|
# MEMORY tuning
|
|
#
|
|
|
|
THP_ENABLE="/sys/kernel/mm/transparent_hugepage/enabled"
|
|
THP_SAVE="${STORAGE}/thp${STORAGE_SUFFIX}"
|
|
|
|
[ -e "$THP_ENABLE" ] || THP_ENABLE="/sys/kernel/mm/redhat_transparent_hugepage/enabled"
|
|
|
|
enable_transparent_hugepages() {
|
|
if [ -e $THP_ENABLE ]; then
|
|
cut -f2 -d'[' $THP_ENABLE | cut -f1 -d']' > $THP_SAVE
|
|
(echo always > $THP_ENABLE) &> /dev/null
|
|
fi
|
|
}
|
|
|
|
restore_transparent_hugepages() {
|
|
if [ -e $THP_SAVE ]; then
|
|
(echo $(cat $THP_SAVE) > $THP_ENABLE) &> /dev/null
|
|
rm -f $THP_SAVE
|
|
fi
|
|
}
|
|
|
|
#
|
|
# WIFI tuning
|
|
#
|
|
|
|
# usage: _wifi_set_power_level level
|
|
_wifi_set_power_level() {
|
|
# 0 auto, PM enabled
|
|
# 1-5 least savings and lowest latency - most savings and highest latency
|
|
# 6 disable power savings
|
|
level=$1
|
|
|
|
# do not report errors on systems with no wireless
|
|
[ -e /proc/net/wireless ] || return 0
|
|
|
|
# apply the settings using iwpriv
|
|
ifaces=$(cat /proc/net/wireless | grep -v '|' | sed 's@^ *\([^:]*\):.*@\1@')
|
|
for iface in $ifaces; do
|
|
iwpriv $iface set_power $level
|
|
done
|
|
|
|
# some adapters may rely on sysfs
|
|
for i in /sys/bus/pci/devices/*/power_level; do
|
|
(echo $level > $i) &> /dev/null
|
|
done
|
|
}
|
|
|
|
enable_wifi_powersave() {
|
|
_wifi_set_power_level 5
|
|
}
|
|
|
|
disable_wifi_powersave() {
|
|
_wifi_set_power_level 0
|
|
}
|
|
|
|
#
|
|
# BLUETOOTH tuning
|
|
#
|
|
|
|
disable_bluetooth() {
|
|
hciconfig hci0 down >/dev/null 2>&1
|
|
lsmod | grep -q btusb && rmmod btusb
|
|
}
|
|
|
|
enable_bluetooth() {
|
|
modprobe btusb
|
|
hciconfig hci0 up >/dev/null 2>&1
|
|
}
|
|
|
|
#
|
|
# USB tuning
|
|
#
|
|
|
|
_usb_autosuspend() {
|
|
value=$1
|
|
for i in /sys/bus/usb/devices/*/power/autosuspend; do echo $value > $i; done &> /dev/null
|
|
}
|
|
|
|
enable_usb_autosuspend() {
|
|
_usb_autosuspend 1
|
|
}
|
|
|
|
disable_usb_autosuspend() {
|
|
_usb_autosuspend 0
|
|
}
|
|
|
|
#
|
|
# SOUND CARDS tuning
|
|
#
|
|
|
|
enable_snd_ac97_powersave() {
|
|
save_set_sys ac97 /sys/module/snd_ac97_codec/parameters/power_save Y
|
|
}
|
|
|
|
disable_snd_ac97_powersave() {
|
|
save_set_sys ac97 /sys/module/snd_ac97_codec/parameters/power_save N
|
|
}
|
|
|
|
restore_snd_ac97_powersave() {
|
|
restore_sys ac97 /sys/module/snd_ac97_codec/parameters/power_save $1
|
|
}
|
|
|
|
set_hda_intel_powersave() {
|
|
save_set_sys hda_intel /sys/module/snd_hda_intel/parameters/power_save $1
|
|
}
|
|
|
|
restore_hda_intel_powersave() {
|
|
restore_sys hda_intel /sys/module/snd_hda_intel/parameters/power_save $1
|
|
}
|
|
|
|
#
|
|
# VIDEO CARDS tuning
|
|
#
|
|
|
|
# Power savings settings for Radeon
|
|
# usage: set_radeon_powersave dynpm | default | low | mid | high
|
|
set_radeon_powersave () {
|
|
[ "$1" ] || return
|
|
[ -e /sys/class/drm/card0/device/power_method ] || return
|
|
if [ "$1" = default -o "$1" = auto -o "$1" = low -o "$1" = med -o "$1" = high ]; then
|
|
[ -w /sys/class/drm/card0/device/power_profile ] || return
|
|
save_sys radeon_profile /sys/class/drm/card0/device/power_profile
|
|
save_set_sys radeon_method /sys/class/drm/card0/device/power_method profile
|
|
set_sys /sys/class/drm/card0/device/power_profile "$1"
|
|
elif [ "$1" = dynpm ]; then
|
|
save_sys radeon_profile /sys/class/drm/card0/device/power_profile
|
|
save_set_sys radeon_method /sys/class/drm/card0/device/power_method dynpm
|
|
fi
|
|
}
|
|
|
|
restore_radeon_powersave () {
|
|
restore_sys radeon_method /sys/class/drm/card0/device/power_method profile
|
|
_rrp_method="`get_stored_sys radeon_method`"
|
|
[ -z "$_rrp_method" -o _rrp_method="profile" ] && restore_sys radeon_profile /sys/class/drm/card0/device/power_profile default
|
|
}
|
|
|
|
#
|
|
# SOFTWARE tuning
|
|
#
|
|
|
|
RSYSLOG_CFG="/etc/rsyslog.conf"
|
|
RSYSLOG_SAVE="${STORAGE}/cpuspeed${STORAGE_SUFFIX}"
|
|
|
|
disable_logs_syncing() {
|
|
cp -p $RSYSLOG_CFG $RSYSLOG_SAVE
|
|
sed -i 's/ \/var\/log/-\/var\/log/' $RSYSLOG_CFG
|
|
}
|
|
|
|
restore_logs_syncing() {
|
|
mv -Z $RSYSLOG_SAVE $RSYSLOG_CFG || mv $RSYSLOG_SAVE $RSYSLOG_CFG
|
|
}
|
|
|
|
#
|
|
# HARDWARE SPECIFIC tuning
|
|
#
|
|
|
|
# Asus EEE with Intel Atom
|
|
_eee_fsb_control() {
|
|
value=$1
|
|
if [ -e /sys/devices/platform/eeepc/she ]; then
|
|
echo $value > /sys/devices/platform/eeepc/she
|
|
elif [ -e /sys/devices/platform/eeepc/cpufv ]; then
|
|
echo $value > /sys/devices/platform/eeepc/cpufv
|
|
elif [ -e /sys/devices/platform/eeepc-wmi/cpufv ]; then
|
|
echo $value > /sys/devices/platform/eeepc-wmi/cpufv
|
|
fi
|
|
}
|
|
|
|
eee_set_reduced_fsb() {
|
|
_eee_fsb_control 2
|
|
}
|
|
|
|
eee_set_normal_fsb() {
|
|
_eee_fsb_control 1
|
|
}
|
|
|
|
#
|
|
# modprobe configuration handling
|
|
#
|
|
|
|
kvm_modprobe_file=/etc/modprobe.d/kvm.rt.tuned.conf
|
|
|
|
teardown_kvm_mod_low_latency()
|
|
{
|
|
rm -f $kvm_modprobe_file
|
|
}
|
|
|
|
setup_kvm_mod_low_latency()
|
|
{
|
|
local HAS_KPS=""
|
|
local HAS_NX_HP=""
|
|
local HAS_PLE_GAP=""
|
|
local WANTS_KPS=""
|
|
local WANTS_NX_HP=""
|
|
local WANTS_PLE_GAP=""
|
|
|
|
if ! modinfo kvm >/dev/null; then
|
|
teardown_kvm_mod_low_latency
|
|
return 0
|
|
fi
|
|
|
|
modinfo -p kvm | grep -q kvmclock_periodic_sync && HAS_KPS=1
|
|
modinfo -p kvm | grep -q nx_huge_pages && HAS_NX_HP=1
|
|
modinfo -p kvm_intel 2>/dev/null | grep -q ple_gap && HAS_PLE_GAP=1
|
|
grep -qs kvmclock_periodic_sync "$kvm_modprobe_file" && WANTS_KPS=1
|
|
grep -qs nx_huge_pages "$kvm_modprobe_file" && WANTS_NX_HP=1
|
|
grep -qs ple_gap "$kvm_modprobe_file" && WANTS_PLE_GAP=1
|
|
|
|
if [ "$HAS_KPS" != "$WANTS_KPS" -o "$HAS_PLE_GAP" != "$WANTS_PLE_GAP" -o \
|
|
"$HAS_NX_HP" != "$WANTS_NX_HP" ]; then
|
|
teardown_kvm_mod_low_latency
|
|
[ "$HAS_KPS" ] && echo "options kvm kvmclock_periodic_sync=0" > $kvm_modprobe_file
|
|
[ "$HAS_NX_HP" ] && echo "options kvm nx_huge_pages=0" >> $kvm_modprobe_file
|
|
[ "$HAS_PLE_GAP" ] && echo "options kvm_intel ple_gap=0" >> $kvm_modprobe_file
|
|
fi
|
|
return 0
|
|
}
|
|
|
|
#
|
|
# KSM
|
|
#
|
|
|
|
KSM_SERVICES="ksm ksmtuned"
|
|
KSM_RUN_PATH=/sys/kernel/mm/ksm/run
|
|
KSM_MASK_FILE="${STORAGE_PERSISTENT}/ksm-masked"
|
|
|
|
disable_ksm()
|
|
{
|
|
if [ ! -f $KSM_MASK_FILE ]; then
|
|
# Always create $KSM_MASK_FILE, since we don't want to
|
|
# run any systemctl commands during boot
|
|
if ! touch $KSM_MASK_FILE; then
|
|
die "failed to create $KSM_MASK_FILE"
|
|
fi
|
|
# Do not run any systemctl commands if $KSM_SERVICES units do not exist
|
|
systemctl cat -- $KSM_SERVICES &> /dev/null || return 0
|
|
systemctl --now --quiet mask $KSM_SERVICES
|
|
# Unmerge all shared pages
|
|
test -f $KSM_RUN_PATH && echo 2 > $KSM_RUN_PATH
|
|
fi
|
|
}
|
|
|
|
# Should only be called when full_rollback == true
|
|
enable_ksm()
|
|
{
|
|
if [ -f $KSM_MASK_FILE ]; then
|
|
# Do not run any systemctl commands if $KSM_SERVICES units do not exist
|
|
systemctl cat -- $KSM_SERVICES &> /dev/null || return 0
|
|
if systemctl --quiet unmask $KSM_SERVICES; then
|
|
rm -f $KSM_MASK_FILE
|
|
fi
|
|
fi
|
|
}
|
|
|
|
die() {
|
|
echo "$@" >&2
|
|
exit 1
|
|
}
|
|
|
|
#
|
|
# ACTION PROCESSING
|
|
#
|
|
|
|
error_not_implemented() {
|
|
echo "tuned: script function '$1' is not implemented." >&2
|
|
}
|
|
|
|
# implicit actions, will be used if not provided by profile script:
|
|
#
|
|
# * start must be implemented
|
|
# * stop must be implemented
|
|
|
|
start() {
|
|
error_not_implemented start
|
|
return 16
|
|
}
|
|
|
|
stop() {
|
|
error_not_implemented stop
|
|
return 16
|
|
}
|
|
|
|
#
|
|
# main processing
|
|
#
|
|
|
|
process() {
|
|
ARG="$1"
|
|
shift
|
|
case "$ARG" in
|
|
start)
|
|
start "$@"
|
|
RETVAL=$?
|
|
;;
|
|
stop)
|
|
stop "$@"
|
|
RETVAL=$?
|
|
;;
|
|
verify)
|
|
if declare -f verify &> /dev/null;
|
|
then
|
|
verify "$@"
|
|
else
|
|
:
|
|
fi
|
|
RETVAL=$?
|
|
;;
|
|
*)
|
|
echo $"Usage: $0 {start|stop|verify}"
|
|
RETVAL=2
|
|
;;
|
|
esac
|
|
|
|
exit $RETVAL
|
|
}
|