• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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