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#      `expr` can deal with ints > INT32_MAX, but if compares cannot. This is why we use MHz.
32#      `expr` can sometimes evaluate right-to-left. This is why we use parens.
33#      Everything below the initial host-check isn't bash - Android uses mksh
34#      mksh allows `\n` in an echo, bash doesn't
35#      can't use `awk`
36
37CPU_TARGET_FREQ_PERCENT=50
38GPU_TARGET_FREQ_PERCENT=50
39
40if [ "`command -v getprop`" == "" ]; then
41    if [ -n "`command -v adb`" ]; then
42        echo ""
43        echo "Pushing $0 and running it on device..."
44        dest=/data/local/tmp/`basename $0`
45        adb push $0 ${dest}
46        adb shell ${dest}
47        adb shell rm ${dest}
48        exit
49    else
50        echo "Could not find adb. Options are:"
51        echo "  1. Ensure adb is on your \$PATH"
52        echo "  2. Use './gradlew lockClocks'"
53        echo "  3. Manually adb push this script to your device, and run it there"
54        exit -1
55    fi
56fi
57
58# require root
59if [ "`id -u`" -ne "0" ]; then
60    echo "Not running as root, cannot lock clocks, aborting"
61    exit -1
62fi
63
64DEVICE=`getprop ro.product.device`
65MODEL=`getprop ro.product.model`
66
67# Find CPU max frequency, and lock big cores to an available frequency
68# that's >= $CPU_TARGET_FREQ_PERCENT% of max. Disable other cores.
69function_lock_cpu() {
70    CPU_BASE=/sys/devices/system/cpu
71    GOV=cpufreq/scaling_governor
72
73    # Find max CPU freq, and associated list of available freqs
74    cpuMaxFreq=0
75    cpuAvailFreqCmpr=0
76    cpuAvailFreq=0
77    enableIndices=''
78    disableIndices=''
79    cpu=0
80    while [ -f ${CPU_BASE}/cpu${cpu}/online ]; do
81        # enable core, so we can find its frequencies
82        echo 1 > ${CPU_BASE}/cpu${cpu}/online
83
84        maxFreq=`cat ${CPU_BASE}/cpu$cpu/cpufreq/cpuinfo_max_freq`
85        availFreq=`cat ${CPU_BASE}/cpu$cpu/cpufreq/scaling_available_frequencies`
86        availFreqCmpr=${availFreq// /-}
87
88        if [ ${maxFreq} -gt ${cpuMaxFreq} ]; then
89            # new highest max freq, look for cpus with same max freq and same avail freq list
90            cpuMaxFreq=${maxFreq}
91            cpuAvailFreq=${availFreq}
92            cpuAvailFreqCmpr=${availFreqCmpr}
93
94            if [ -z ${disableIndices} ]; then
95                disableIndices="$enableIndices"
96            else
97                disableIndices="$disableIndices $enableIndices"
98            fi
99            enableIndices=${cpu}
100        elif [ ${maxFreq} == ${cpuMaxFreq} ] && [ ${availFreqCmpr} == ${cpuAvailFreqCmpr} ]; then
101            enableIndices="$enableIndices $cpu"
102        else
103            disableIndices="$disableIndices $cpu"
104        fi
105        cpu=$(($cpu + 1))
106    done
107
108    # Chose a frequency to lock to that's >= $CPU_TARGET_FREQ_PERCENT% of max
109    # (below, 100M = 1K for KHz->MHz * 100 for %)
110    TARGET_FREQ_MHZ=`expr \( ${cpuMaxFreq} \* ${CPU_TARGET_FREQ_PERCENT} \) \/ 100000`
111    chosenFreq=0
112    for freq in ${cpuAvailFreq}; do
113        freqMhz=`expr ${freq} \/ 1000`
114        if [ ${freqMhz} -ge ${TARGET_FREQ_MHZ} ]; then
115            chosenFreq=${freq}
116            break
117        fi
118    done
119
120    # enable 'big' CPUs
121    for cpu in ${enableIndices}; do
122        freq=${CPU_BASE}/cpu$cpu/cpufreq
123
124        echo 1 > ${CPU_BASE}/cpu${cpu}/online
125        echo userspace > ${CPU_BASE}/cpu${cpu}/${GOV}
126        echo ${chosenFreq} > ${freq}/scaling_max_freq
127        echo ${chosenFreq} > ${freq}/scaling_min_freq
128        echo ${chosenFreq} > ${freq}/scaling_setspeed
129
130        # validate setting the freq worked
131        obsCur=`cat ${freq}/scaling_cur_freq`
132        obsMin=`cat ${freq}/scaling_min_freq`
133        obsMax=`cat ${freq}/scaling_max_freq`
134        if [ obsCur -ne ${chosenFreq} ] || [ obsMin -ne ${chosenFreq} ] || [ obsMax -ne ${chosenFreq} ]; then
135            echo "Failed to set CPU$cpu to $chosenFreq Hz! Aborting..."
136            echo "scaling_cur_freq = $obsCur"
137            echo "scaling_min_freq = $obsMin"
138            echo "scaling_max_freq = $obsMax"
139            exit -1
140        fi
141    done
142
143    # disable other CPUs (Note: important to enable big cores first!)
144    for cpu in ${disableIndices}; do
145      echo 0 > ${CPU_BASE}/cpu${cpu}/online
146    done
147
148    echo "\nLocked CPUs ${enableIndices// /,} to $chosenFreq / $maxFreq KHz"
149    echo "Disabled CPUs ${disableIndices// /,}"
150}
151
152# If we have a Qualcomm GPU, find its max frequency, and lock to
153# an available frequency that's >= GPU_TARGET_FREQ_PERCENT% of max.
154function_lock_gpu_kgsl() {
155    if [ ! -d /sys/class/kgsl/kgsl-3d0/ ]; then
156        # not kgsl, abort
157        echo "\nCurrently don't support locking GPU clocks of $MODEL ($DEVICE)"
158        return -1
159    fi
160    if [ ${DEVICE} == "walleye" ] || [ ${DEVICE} == "taimen" ]; then
161        # Workaround crash
162        echo "\nUnable to lock GPU clocks of $MODEL ($DEVICE)"
163        return -1
164    fi
165
166    GPU_BASE=/sys/class/kgsl/kgsl-3d0
167
168    gpuMaxFreq=0
169    gpuAvailFreq=`cat $GPU_BASE/devfreq/available_frequencies`
170    for freq in ${gpuAvailFreq}; do
171        if [ ${freq} -gt ${gpuMaxFreq} ]; then
172            gpuMaxFreq=${freq}
173        fi
174    done
175
176    # (below, 100M = 1M for MHz * 100 for %)
177    TARGET_FREQ_MHZ=`expr \( ${gpuMaxFreq} \* ${GPU_TARGET_FREQ_PERCENT} \) \/ 100000000`
178
179    chosenFreq=${gpuMaxFreq}
180    index=0
181    chosenIndex=0
182    for freq in ${gpuAvailFreq}; do
183        freqMhz=`expr ${freq} \/ 1000000`
184        if [ ${freqMhz} -ge ${TARGET_FREQ_MHZ} ] && [ ${chosenFreq} -ge ${freq} ]; then
185            # note avail freq are generally in reverse order, so we don't break out of this loop
186            chosenFreq=${freq}
187            chosenIndex=${index}
188        fi
189        index=$(($index + 1))
190    done
191    lastIndex=$(($index - 1))
192
193    firstFreq=`echo $gpuAvailFreq | cut -d" " -f1`
194
195    if [ ${gpuMaxFreq} != ${firstFreq} ]; then
196        # pwrlevel is index of desired freq among available frequencies, from highest to lowest.
197        # If gpuAvailFreq appears to be in-order, reverse the index
198        chosenIndex=$(($lastIndex - $chosenIndex))
199    fi
200
201    echo 0 > ${GPU_BASE}/bus_split
202    echo 1 > ${GPU_BASE}/force_clk_on
203    echo 10000 > ${GPU_BASE}/idle_timer
204
205    echo performance > ${GPU_BASE}/devfreq/governor
206
207    # NOTE: we store in min/max twice, because we don't know if we're increasing
208    # or decreasing, and it's invalid to try and set min > max, or max < min
209    echo ${chosenFreq} > ${GPU_BASE}/devfreq/min_freq
210    echo ${chosenFreq} > ${GPU_BASE}/devfreq/max_freq
211    echo ${chosenFreq} > ${GPU_BASE}/devfreq/min_freq
212    echo ${chosenFreq} > ${GPU_BASE}/devfreq/max_freq
213    echo ${chosenIndex} > ${GPU_BASE}/min_pwrlevel
214    echo ${chosenIndex} > ${GPU_BASE}/max_pwrlevel
215    echo ${chosenIndex} > ${GPU_BASE}/min_pwrlevel
216    echo ${chosenIndex} > ${GPU_BASE}/max_pwrlevel
217
218    obsCur=`cat ${GPU_BASE}/devfreq/cur_freq`
219    obsMin=`cat ${GPU_BASE}/devfreq/min_freq`
220    obsMax=`cat ${GPU_BASE}/devfreq/max_freq`
221    if [ obsCur -ne ${chosenFreq} ] || [ obsMin -ne ${chosenFreq} ] || [ obsMax -ne ${chosenFreq} ]; then
222        echo "Failed to set GPU to $chosenFreq Hz! Aborting..."
223        echo "cur_freq = $obsCur"
224        echo "min_freq = $obsMin"
225        echo "max_freq = $obsMax"
226        echo "index = $chosenIndex"
227        exit -1
228    fi
229    echo "\nLocked GPU to $chosenFreq / $gpuMaxFreq Hz"
230}
231
232# kill processes that manage thermals / scaling
233stop thermal-engine
234stop perfd
235stop vendor.thermal-engine
236stop vendor.perfd
237
238function_lock_cpu
239
240function_lock_gpu_kgsl
241
242# Memory bus - hardcoded per-device for now
243if [ ${DEVICE} == "marlin" ] || [ ${DEVICE} == "sailfish" ]; then
244    echo 13763 > /sys/class/devfreq/soc:qcom,gpubw/max_freq
245else
246    echo "\nUnable to lock memory bus of $MODEL ($DEVICE)."
247fi
248
249echo "\n$DEVICE clocks have been locked - to reset, reboot the device\n"