1# 2# Copyright (C) 2018 The Android Open Source Project 3# 4# Licensed under the Apache License, Version 2.0 (the "License"); 5# you may not use this file except in compliance with the License. 6# You may obtain a copy of the License at 7# 8# http://www.apache.org/licenses/LICENSE-2.0 9# 10# Unless required by applicable law or agreed to in writing, software 11# distributed under the License is distributed on an "AS IS" BASIS, 12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13# See the License for the specific language governing permissions and 14# limitations under the License. 15# 16 17################################################################# 18### 19### DO NOT MODIFY THIS FILE 20### This is a copy of androidx's benchmark/lockClocks.sh 21### Make changes there instead then copy here! 22### 23################################################################# 24 25# This script can be used to lock device clocks to stable levels for comparing 26# different versions of software. Since the clock levels are not necessarily 27# indicative of real world behavior, this should **never** be used to compare 28# performance between different device models. 29 30# Fun notes for maintaining this file: 31# $((arithmetic expressions)) can deal with ints > INT32_MAX, but if compares cannot. This is 32# why we use MHz. 33# $((arithmetic expressions)) can sometimes evaluate right-to-left. This is why we use parens. 34# Everything below the initial host-check isn't bash - Android uses mksh 35# mksh allows `\n` in an echo, bash doesn't 36# can't use `awk` 37# can't use `sed` 38# can't use `cut` on < L 39# can't use `expr` on < L 40 41ARG_CORES=${1:-big} 42 43CPU_TARGET_FREQ_PERCENT=50 44GPU_TARGET_FREQ_PERCENT=50 45 46if [ "`command -v getprop`" == "" ]; then 47 if [ -n "`command -v adb`" ]; then 48 echo "" 49 echo "Pushing $0 and running it on device..." 50 dest=/data/local/tmp/`basename $0` 51 adb push $0 ${dest} 52 adb shell ${dest} $@ 53 adb shell rm ${dest} 54 exit 55 else 56 echo "Could not find adb. Options are:" 57 echo " 1. Ensure adb is on your \$PATH" 58 echo " 2. Use './gradlew lockClocks'" 59 echo " 3. Manually adb push this script to your device, and run it there" 60 exit -1 61 fi 62fi 63 64# require root 65if [[ `id` != "uid=0"* ]]; then 66 echo "Not running as root, cannot lock clocks, aborting" 67 exit -1 68fi 69 70DEVICE=`getprop ro.product.device` 71MODEL=`getprop ro.product.model` 72 73if [ "$ARG_CORES" == "big" ]; then 74 CPU_IDEAL_START_FREQ_KHZ=0 75elif [ "$ARG_CORES" == "little" ]; then 76 CPU_IDEAL_START_FREQ_KHZ=100000000 ## finding min of max freqs, so start at 100M KHz (100 GHz) 77else 78 echo "Invalid argument \$1 for ARG_CORES, should be 'big' or 'little', but was $ARG_CORES" 79 exit -1 80fi 81 82function_core_check() { 83 if [ "$ARG_CORES" == "big" ]; then 84 [ $1 -gt $2 ] 85 elif [ "$ARG_CORES" == "little" ]; then 86 [ $1 -lt $2 ] 87 else 88 echo "Invalid argument \$1 for ARG_CORES, should be 'big' or 'little', but was $ARG_CORES" 89 exit -1 90 fi 91} 92 93function_setup_go() { 94 if [ -f /d/fpsgo/common/force_onoff ]; then 95 # Disable fpsgo 96 echo 0 > /d/fpsgo/common/force_onoff 97 fpsgoState=`cat /d/fpsgo/common/force_onoff` 98 if [ "$fpsgoState" != "0" ] && [ "$fpsgoState" != "force off" ]; then 99 echo "Failed to disable fpsgo" 100 exit -1 101 fi 102 fi 103} 104 105# Find the min or max (little vs big) of CPU max frequency, and lock cores of the selected type to 106# an available frequency that's >= $CPU_TARGET_FREQ_PERCENT% of max. Disable other cores. 107function_lock_cpu() { 108 CPU_BASE=/sys/devices/system/cpu 109 GOV=cpufreq/scaling_governor 110 111 # Options to make clock locking on go devices more sticky. 112 function_setup_go 113 114 # Find max CPU freq, and associated list of available freqs 115 cpuIdealFreq=$CPU_IDEAL_START_FREQ_KHZ 116 cpuAvailFreqCmpr=0 117 cpuAvailFreq=0 118 enableIndices='' 119 disableIndices='' 120 cpu=0 121 while [ -d ${CPU_BASE}/cpu${cpu}/cpufreq ]; do 122 # Try to enable core, so we can find its frequencies. 123 # Note: In cases where the online file is inaccessible, it represents a 124 # core which cannot be turned off, so we simply assume it is enabled if 125 # this command fails. 126 if [ -f "$CPU_BASE/cpu$cpu/online" ]; then 127 echo 1 > ${CPU_BASE}/cpu${cpu}/online || true 128 fi 129 130 # set userspace governor on all CPUs to ensure freq scaling is disabled 131 echo userspace > ${CPU_BASE}/cpu${cpu}/${GOV} 132 133 maxFreq=`cat ${CPU_BASE}/cpu$cpu/cpufreq/cpuinfo_max_freq` 134 availFreq=`cat ${CPU_BASE}/cpu$cpu/cpufreq/scaling_available_frequencies` 135 availFreqCmpr=${availFreq// /-} 136 137 if (function_core_check $maxFreq $cpuIdealFreq); then 138 # new min/max of max freq, look for cpus with same max freq and same avail freq list 139 cpuIdealFreq=${maxFreq} 140 cpuAvailFreq=${availFreq} 141 cpuAvailFreqCmpr=${availFreqCmpr} 142 143 if [ -z "$disableIndices" ]; then 144 disableIndices="$enableIndices" 145 else 146 disableIndices="$disableIndices $enableIndices" 147 fi 148 enableIndices=${cpu} 149 elif [ ${maxFreq} == ${cpuIdealFreq} ] && [ ${availFreqCmpr} == ${cpuAvailFreqCmpr} ]; then 150 enableIndices="$enableIndices $cpu" 151 else 152 if [ -z "$disableIndices" ]; then 153 disableIndices="$cpu" 154 else 155 disableIndices="$disableIndices $cpu" 156 fi 157 fi 158 159 cpu=$(($cpu + 1)) 160 done 161 162 # check that some CPUs will be enabled 163 if [ -z "$enableIndices" ]; then 164 echo "Failed to find any $ARG_CORES cores to enable, aborting." 165 exit -1 166 fi 167 168 # Chose a frequency to lock to that's >= $CPU_TARGET_FREQ_PERCENT% of max 169 # (below, 100M = 1K for KHz->MHz * 100 for %) 170 TARGET_FREQ_MHZ=$(( ($cpuIdealFreq * $CPU_TARGET_FREQ_PERCENT) / 100000 )) 171 chosenFreq=0 172 chosenFreqDiff=100000000 173 for freq in ${cpuAvailFreq}; do 174 freqMhz=$(( ${freq} / 1000 )) 175 if [ ${freqMhz} -ge ${TARGET_FREQ_MHZ} ]; then 176 newChosenFreqDiff=$(( $freq - $TARGET_FREQ_MHZ )) 177 if [ $newChosenFreqDiff -lt $chosenFreqDiff ]; then 178 chosenFreq=${freq} 179 chosenFreqDiff=$(( $chosenFreq - $TARGET_FREQ_MHZ )) 180 fi 181 fi 182 done 183 184 # Lock wembley clocks using high-priority op code method. 185 # This block depends on the shell utility awk, which is only available on API 27+ 186 if [ "$DEVICE" == "wembley" ]; then 187 # Get list of available frequencies to lock to by parsing the op-code list. 188 AVAIL_OP_FREQS=`cat /proc/cpufreq/MT_CPU_DVFS_LL/cpufreq_oppidx \ 189 | awk '{print $2}' \ 190 | tail -n +3 \ 191 | while read line; do 192 echo "${line:1:${#line}-2}" 193 done` 194 195 # Compute the closest available frequency to the desired frequency, $chosenFreq. 196 # This assumes the op codes listen in /proc/cpufreq/MT_CPU_DVFS_LL/cpufreq_oppidx are listed 197 # in order and 0-indexed. 198 opCode=-1 199 opFreq=0 200 currOpCode=-1 201 for currOpFreq in $AVAIL_OP_FREQS; do 202 currOpCode=$((currOpCode + 1)) 203 204 prevDiff=$((chosenFreq-opFreq)) 205 prevDiff=`function_abs $prevDiff` 206 currDiff=$((chosenFreq-currOpFreq)) 207 currDiff=`function_abs $currDiff` 208 if [ $currDiff -lt $prevDiff ]; then 209 opCode="$currOpCode" 210 opFreq="$currOpFreq" 211 fi 212 done 213 214 echo "$opCode" > /proc/ppm/policy/ut_fix_freq_idx 215 fi 216 217 # enable 'big' CPUs 218 for cpu in ${enableIndices}; do 219 freq=${CPU_BASE}/cpu$cpu/cpufreq 220 221 # Try to enable core, so we can find its frequencies. 222 # Note: In cases where the online file is inaccessible, it represents a 223 # core which cannot be turned off, so we simply assume it is enabled if 224 # this command fails. 225 if [ -f "$CPU_BASE/cpu$cpu/online" ]; then 226 echo 1 > ${CPU_BASE}/cpu${cpu}/online || true 227 fi 228 229 # scaling_max_freq must be set before scaling_min_freq 230 echo ${chosenFreq} > ${freq}/scaling_max_freq 231 echo ${chosenFreq} > ${freq}/scaling_min_freq 232 echo ${chosenFreq} > ${freq}/scaling_setspeed 233 234 # Give system a bit of time to propagate the change to scaling_setspeed. 235 sleep 0.1 236 237 # validate setting the freq worked 238 obsCur=`cat ${freq}/scaling_cur_freq` 239 obsMin=`cat ${freq}/scaling_min_freq` 240 obsMax=`cat ${freq}/scaling_max_freq` 241 if [ "$obsCur" -ne "$chosenFreq" ] || [ "$obsMin" -ne "$chosenFreq" ] || [ "$obsMax" -ne "$chosenFreq" ]; then 242 echo "Failed to set CPU$cpu to $chosenFreq Hz! Aborting..." 243 echo "scaling_cur_freq = $obsCur" 244 echo "scaling_min_freq = $obsMin" 245 echo "scaling_max_freq = $obsMax" 246 exit -1 247 fi 248 done 249 250 # disable other CPUs (Note: important to enable big cores first!) 251 for cpu in ${disableIndices}; do 252 echo 0 > ${CPU_BASE}/cpu${cpu}/online 253 done 254 255 echo "==================================" 256 echo "Locked CPUs ${enableIndices// /,} to $chosenFreq / $cpuIdealFreq KHz" 257 echo "Disabled CPUs ${disableIndices// /,}" 258 echo "==================================" 259} 260 261# Returns the absolute value of the first arg passed to this helper. 262function_abs() { 263 n=$1 264 if [ $n -lt 0 ]; then 265 echo "$((n * -1 ))" 266 else 267 echo "$n" 268 fi 269} 270 271# If we have a Qualcomm GPU, find its max frequency, and lock to 272# an available frequency that's >= GPU_TARGET_FREQ_PERCENT% of max. 273function_lock_gpu_kgsl() { 274 if [ ! -d /sys/class/kgsl/kgsl-3d0/ ]; then 275 # not kgsl, abort 276 echo "Currently don't support locking GPU clocks of $MODEL ($DEVICE)" 277 return -1 278 fi 279 if [ ${DEVICE} == "walleye" ] || [ ${DEVICE} == "taimen" ]; then 280 # Workaround crash 281 echo "Unable to lock GPU clocks of $MODEL ($DEVICE)" 282 return -1 283 fi 284 285 GPU_BASE=/sys/class/kgsl/kgsl-3d0 286 287 gpuMaxFreq=0 288 gpuAvailFreq=`cat $GPU_BASE/devfreq/available_frequencies` 289 for freq in ${gpuAvailFreq}; do 290 if [ ${freq} -gt ${gpuMaxFreq} ]; then 291 gpuMaxFreq=${freq} 292 fi 293 done 294 295 # (below, 100M = 1M for MHz * 100 for %) 296 TARGET_FREQ_MHZ=$(( (${gpuMaxFreq} * ${GPU_TARGET_FREQ_PERCENT}) / 100000000 )) 297 298 chosenFreq=${gpuMaxFreq} 299 index=0 300 chosenIndex=0 301 for freq in ${gpuAvailFreq}; do 302 freqMhz=$(( ${freq} / 1000000 )) 303 if [ ${freqMhz} -ge ${TARGET_FREQ_MHZ} ] && [ ${chosenFreq} -ge ${freq} ]; then 304 # note avail freq are generally in reverse order, so we don't break out of this loop 305 chosenFreq=${freq} 306 chosenIndex=${index} 307 fi 308 index=$(($index + 1)) 309 done 310 lastIndex=$(($index - 1)) 311 312 firstFreq=`function_cut_first_from_space_seperated_list $gpuAvailFreq` 313 314 if [ ${gpuMaxFreq} != ${firstFreq} ]; then 315 # pwrlevel is index of desired freq among available frequencies, from highest to lowest. 316 # If gpuAvailFreq appears to be in-order, reverse the index 317 chosenIndex=$(($lastIndex - $chosenIndex)) 318 fi 319 320 echo 0 > ${GPU_BASE}/bus_split 321 echo 1 > ${GPU_BASE}/force_clk_on 322 echo 10000 > ${GPU_BASE}/idle_timer 323 324 echo performance > ${GPU_BASE}/devfreq/governor 325 326 # NOTE: we store in min/max twice, because we don't know if we're increasing 327 # or decreasing, and it's invalid to try and set min > max, or max < min 328 echo ${chosenFreq} > ${GPU_BASE}/devfreq/min_freq 329 echo ${chosenFreq} > ${GPU_BASE}/devfreq/max_freq 330 echo ${chosenFreq} > ${GPU_BASE}/devfreq/min_freq 331 echo ${chosenFreq} > ${GPU_BASE}/devfreq/max_freq 332 echo ${chosenIndex} > ${GPU_BASE}/min_pwrlevel 333 echo ${chosenIndex} > ${GPU_BASE}/max_pwrlevel 334 echo ${chosenIndex} > ${GPU_BASE}/min_pwrlevel 335 echo ${chosenIndex} > ${GPU_BASE}/max_pwrlevel 336 337 obsCur=`cat ${GPU_BASE}/devfreq/cur_freq` 338 obsMin=`cat ${GPU_BASE}/devfreq/min_freq` 339 obsMax=`cat ${GPU_BASE}/devfreq/max_freq` 340 if [ obsCur -ne ${chosenFreq} ] || [ obsMin -ne ${chosenFreq} ] || [ obsMax -ne ${chosenFreq} ]; then 341 echo "Failed to set GPU to $chosenFreq Hz! Aborting..." 342 echo "cur_freq = $obsCur" 343 echo "min_freq = $obsMin" 344 echo "max_freq = $obsMax" 345 echo "index = $chosenIndex" 346 exit -1 347 fi 348 echo "Locked GPU to $chosenFreq / $gpuMaxFreq Hz" 349} 350 351# cut is not available on some devices (Nexus 5 running LRX22C). 352function_cut_first_from_space_seperated_list() { 353 list=$1 354 355 for freq in $list; do 356 echo $freq 357 break 358 done 359} 360 361# kill processes that manage thermals / scaling 362stop thermal-engine || true 363stop perfd || true 364stop vendor.thermal-engine || true 365stop vendor.perfd || true 366setprop vendor.powerhal.init 0 || true 367setprop ctl.interface_restart android.hardware.power@1.0::IPower/default || true 368 369function_lock_cpu 370 371if [ "$DEVICE" -ne "wembley" ]; then 372 function_lock_gpu_kgsl 373else 374 echo "Unable to lock gpu clocks of $MODEL ($DEVICE)." 375fi 376 377# Memory bus - hardcoded per-device for now 378if [ ${DEVICE} == "marlin" ] || [ ${DEVICE} == "sailfish" ]; then 379 echo 13763 > /sys/class/devfreq/soc:qcom,gpubw/max_freq 380else 381 echo "Unable to lock memory bus of $MODEL ($DEVICE)." 382fi 383 384echo "$DEVICE clocks have been locked - to reset, reboot the device" 385