#!/bin/bash . /usr/share/undervolt/functions.bash || { printf "ERROR: Could not load functions.bash\n" exit 1 } # http://phc.athousandnights.de/ printf "\n I assume you have linux-phc correctly installed and working. This script will optimize your voltages at every speed setting by systematically lowering them while stressing the CPU. Each voltage will be turned down until your system crashes, and the final setting for that voltage will be 2 VIDs above that to \"ensure\" stability. WARNING: This script will crash your system as many times as there are VIDs to tweak. You might destroy your hardware, break laws and/or die in vain if you continue.\n\n" confirm || exit 0 cpufreq=/sys/devices/system/cpu/cpu0/cpufreq phc_vids=$cpufreq/phc_vids printf "\n\nWill use current directory to store/retrieve test results.\n" printf "\nRead phc_default_vids:\n" cat $cpufreq/phc_default_vids > /dev/null check || exit 1 def_vids=`cat $cpufreq/phc_default_vids` if [ -f phc_tweaked_vids ]; then printf "\nLoad VIDs from 'phc_tweaked_vids'\n" cur_vids=`cat phc_tweaked_vids` else printf "\nRead default VIDs.\n" cur_vids="$def_vids" fi count_phc=`printf "$def_vids" | awk '{print NF}'` count_tweak=`printf "$cur_vids" | awk '{printf NF}'` if [ "$count_phc" != "$count_tweak" ]; then printf "$tcf00> ERROR:$tcRst Wrong VID count!\n" exit 1 fi let count_phc-- check || { printf "$tcf00> ERROR:$tcRst Number of VIDs is zero!\n" exit 1 } if [[ -f phc_tweaked_vids && -f phc_cur_pos ]]; then printf "Load position from 'phc_cur_pos'\n" cur_pos=`cat phc_cur_pos` let ++cur_pos check || exit 1 else printf "Reset position to 0.\n" cur_pos=0 fi printf "Read available frequencies.\n" freqs=`cat $cpufreq/scaling_available_frequencies` c=0 for i in $freqs; do let c++ freq[c]=$i done if [ "$c" != "$count_tweak" ]; then printf "$tcf00> ERROR:$tcRst Number of frequencies ($c) and VIDs ($count_tweak) do not match!\n" exit 1 fi check #printf "$cur_vids" | awk '{for (i=1; i<=NF; i++) print $i}' c=0 for i in $cur_vids; do let c++ vid[c]=$i if [ "$c" -lt "$cur_pos" ]; then vids_done="$vids_done$i " fi if [ "$c" = "$cur_pos" ]; then printf "\nLast VID: $i\n" let vid[c]+=2 if [ "${vid[$c]}" -gt "${vid[$(( $c - 1 ))]}" ]; then printf "Replace with VID from previous position.\n" let vid[c]=vid[c-1] else printf "Increase by +2\n" fi vid_last="${vid[c]} " fi if [ "$(( c - 1 ))" = "$cur_pos" ]; then vid_next="$i" else if [ "$c" -gt "$cur_pos" ]; then vids_rem="$vids_rem $i" fi fi done printf "\nDefault VIDs: $def_vids Current VIDs: $tc0f0$vids_done$tcf00$vid_last$tcff0$vid_next$tcRst$vids_rem\n" printf "$vids_done$vid_last$vid_next$vids_rem" > phc_tweaked_vids printf "$cur_pos" > phc_cur_pos if [ "$cur_pos" -gt "$count_phc" ]; then printf "\nAll VIDs have been tweaked! Results are in the file 'phc_tweaked_vids' - use with care.\n" printf "\nAll done! - Have a nice day.\n" exit 0 fi if [ "x$vid_last" != "x" ]; then if [ "$vid_next" -gt "${vid[$cur_pos]}" ]; then printf "\nNext VID higher than last - copying." vid[$(( cur_pos + 1 ))]=${vid[$cur_pos]} fi fi let ++cur_pos printf "\nSwitch to 'userspace' scaling governor.\n" printf "userspace" | tee $cpufreq/scaling_governor > /dev/null check || exit 1 printf "Set frequency to ${freq[$cur_pos]}.\n" printf "${freq[$cur_pos]}" | tee $cpufreq/scaling_setspeed > /dev/null check || exit 1 printf "Run burnMMX.\n" grep [b]urnMMX > /dev/null && printf "...already running.\n" || burnMMX & printf " PID: $!\n" recover () { printf "\n\nRecovering CPU.\n" printf "$vids_done$vid_last$((${vid[$cur_pos]} + 2))$vids_rem" | tee $cpufreq/phc_vids > /dev/null printf "ondemand" | tee $cpufreq/scaling_governor > /dev/null pkill burnMMX printf "\nRun this script again to continue the optimization.\n" } printf "\n-----\nStart testing.\n" confirm || { recover exit 1 } while [[ 1 ]]; do let vid[cur_pos]-- printf "\nDefault VIDs: $def_vids Current VIDs: $tc0f0$vids_done$tc0f0$vid_last$tcf00${vid[$cur_pos]}$tcRst$vids_rem Testing VID: ${vid[$cur_pos]} ($(( ${vid[$cur_pos]} * 16 + 700)) mV)\n" printf "$vids_done$vid_last${vid[$cur_pos]}$vids_rem" > phc_tweaked_vids sync if [ "${vid[$cur_pos]}" -lt "0" ]; then printf "\n\nThe lowest acceptable VID is 0." recover exit 0 fi printf "$vids_done$vid_last${vid[$cur_pos]}$vids_rem" | tee $cpufreq/phc_vids > /dev/null c=0 while [ "$c" -lt "30" ]; do ps aux | grep [b]urnMMX > /dev/null || { printf "\nburnMMX crashed!" recover exit 0 } printf "." sleep 0.5 let c++ done done