# # 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/sh "$DISK_QUANTUM_SAVE" &>/dev/null rm -f "$DISK_QUANTUM_SAVE" fi } # # CPU tuning # CPUSPEED_SAVE_FILE="${STORAGE}/cpuspeed${STORAGE_SUFFIX}" CPUSPEED_ORIG_GOV="${STORAGE}/cpuspeed-governor-%s${STORAGE_SUFFIX}" CPUSPEED_STARTED="${STORAGE}/cpuspeed-started" CPUSPEED_CFG="/etc/sysconfig/cpuspeed" CPUSPEED_INIT="/etc/init.d/cpuspeed" # do not use cpuspeed CPUSPEED_USE="0" 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 # always patch cpuspeed configuration if exists, if it doesn't exist and is enabled, # explictly disable it with hint if [ -e $CPUSPEED_INIT ]; then if [ ! -e $CPUSPEED_SAVE_FILE -a -e $CPUSPEED_CFG ]; then cp -p $CPUSPEED_CFG $CPUSPEED_SAVE_FILE sed -e 's/^GOVERNOR=.*/GOVERNOR='$governor'/g' $CPUSPEED_SAVE_FILE > $CPUSPEED_CFG fi else if [ "$CPUSPEED_USE" = "1" ]; then echo >&2 echo "Suggestion: install 'cpuspeed' package to get best tuning results." >&2 echo "Falling back to sysfs control." >&2 echo >&2 fi CPUSPEED_USE="0" fi if [ "$CPUSPEED_USE" = "1" ]; then service cpuspeed status &> /dev/null [ $? -eq 3 ] && touch $CPUSPEED_STARTED || rm -f $CPUSPEED_STARTED service cpuspeed restart &> /dev/null # direct change using sysfs elif [ -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 $CPUSPEED_INIT ]; then if [ -e $CPUSPEED_SAVE_FILE ]; then cp -fp $CPUSPEED_SAVE_FILE $CPUSPEED_CFG rm -f $CPUSPEED_SAVE_FILE fi if [ "$CPUSPEED_USE" = "1" ]; then if [ -e $CPUSPEED_STARTED ]; then service cpuspeed stop &> /dev/null else service cpuspeed restart &> /dev/null fi fi if [ -e $CPUSPEED_STARTED ]; then rm -f $CPUSPEED_STARTED fi else CPUSPEED_USE="0" fi if [ "$CPUSPEED_USE" != "1" -a -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 # 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 relay 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 } irqbalance_banned_cpus_clear() { sed -i '/^IRQBALANCE_BANNED_CPUS=/d' /etc/sysconfig/irqbalance } irqbalance_banned_cpus_setup() { irqbalance_banned_cpus_clear if [ -n "$1" ]; then echo "IRQBALANCE_BANNED_CPUS=$1" >> /etc/sysconfig/irqbalance fi } # # 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_PLE_GAP="" local WANTS_KPS="" local WANTS_PLE_GAP="" modinfo -p kvm | grep -q kvmclock_periodic_sync && HAS_KPS=1 modinfo -p kvm_intel | grep -q ple_gap && HAS_PLE_GAP=1 grep -qs kvmclock_periodic_sync "$kvm_modprobe_file" && WANTS_KPS=1 grep -qs ple_gap "$kvm_modprobe_file" && WANTS_PLE_GAP=1 if [ "$HAS_KPS" != "$WANTS_KPS" -o "$HAS_PLE_GAP" != "$WANTS_PLE_GAP" ]; then teardown_kvm_mod_low_latency [ "$HAS_KPS" ] && echo "options kvm kvmclock_periodic_sync=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 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 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 }