Move GPU locking logic into generic hardware profile

Change-Id: If130b47acdd7f7fc06daa1d4cb5938e4476e0171
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/367776
Reviewed-by: Chris Dalton <csmartdalton@google.com>
Commit-Queue: Nathaniel Nifong <nifong@google.com>
This commit is contained in:
Nathaniel Nifong 2021-02-09 08:58:00 -05:00 committed by Skia Commit-Bot
parent 59e3456695
commit ba4c3086ba
3 changed files with 96 additions and 9 deletions

View File

@ -29,13 +29,14 @@ ninja -C out/arm64 skpbench
## Benchmark an SKP on a connected device.
First, copy the built skpbench binary and an example skp file to the device.
(or pull a skp corpus using instructions in the section below)
```
adb push out/arm64/skpbench /data/local/tmp
adb push /home/nifong/Downloads/foo.skp /data/local/tmp/skps/
```
Run skpbench.py (in my case on a Pixel 3)
Run skpbench.py
```
python tools/skpbench/skpbench.py \
@ -60,7 +61,45 @@ Output appears in the following format
`accum` is the time taken to draw all frames, divided by the number of frames.
`metric` specifies that the unit is ms (milliseconds per frame)
## MSKP corpus
A manually collected corpus of MSKPs from around 30 top apps (using skia via HWUI) and of about 20
actions in RenderEngine exists in a google cloud storage folder managed by skia/infra/bots/assets/mskp/upload.py
To download the fileset, first determine the highest current version of the fileset
```
gsutil ls gs://skia-assets/assets/mskp/
```
Download the latest version.
```
gsutil cp gs://skia-assets/assets/mskp/5.zip ~/Downloads
```
Unzip the archive and adb push it to the device.
To upload a new version of the corpus, use the steps above to download and unzip the last version, change the
content however you need, then Use the upload tool, passing the directory of the altered archive (not a zip file).
Note that you must provide it as an absolute path.
```
python upload.py --target_dir=/home/nifong/scratch/new_mskps
```
The upload script should print a version number.
Finally, submit something like https://skia-review.googlesource.com/c/skia/+/304376
to point jobs at the new version.
## Production
skpbench is run as a tryjob from gerrit, where it uploads the results to perf.skia.org.
TODO(nifong, csmartdalton): elaborate on this section.
Once such job name is `Perf-Android-Clang-Pixel4XL-GPU-Adreno640-arm64-Release-All-Android_Skpbench`
Perf results are available by querying with this or similar.
extra_config = Android_Skpbench
sub_result = accum_cpu_ms
Example perf query
https://perf.skia.org/e/?queries=extra_config%3DAndroid_Skpbench%26sub_result%3Daccum_cpu_ms

View File

@ -13,6 +13,7 @@ class HardwareAndroid(Hardware):
Hardware.__init__(self)
self.warmup_time = 5
self._adb = adb
self.desiredClock = 0.66
if self._adb.root():
self._adb.remount()
@ -35,6 +36,9 @@ class HardwareAndroid(Hardware):
if self._adb.is_root():
# For explanation of variance reducing steps, see
# https://g3doc.corp.google.com/engedu/portal/android/g3doc/learn/develop/performance/content/best/reliable-startup-latency.md?cl=head
self._adb.shell('\n'.join([
# disable bluetooth, wifi, and mobile data.
'''
@ -52,14 +56,12 @@ class HardwareAndroid(Hardware):
# disable ASLR
'''
echo 0 > /proc/sys/kernel/randomize_va_space''',
# stop services which can change clock speed
'''
stop thermal-engine
stop perfd''']))
]))
self.lock_top_three_cores()
self.lock_adreno_gpu()
else:
print("WARNING: no adb root access; results may be unreliable.",
file=sys.stderr)
@ -102,6 +104,10 @@ class HardwareAndroid(Hardware):
Hardware.print_debug_diagnostics(self)
# expects a float between 0 and 100 representing where along the list of freqs to choose a value.
def setDesiredClock(self, c):
self.desiredClock = c / 100
def lock_top_three_cores(self):
# Lock the clocks of the fastest three cores and disable others.
# Assumes root privlidges
@ -120,9 +126,36 @@ class HardwareAndroid(Hardware):
# get a list of available scaling frequencies and pick one 2/3 of the way up.
for i in top_cores:
freqs = self._adb.check('cat /sys/devices/system/cpu/cpu%i/cpufreq/scaling_available_frequencies' % i).split()
speed = freqs[int((len(freqs)-1)*.66)]
speed = freqs[int((len(freqs)-1) * self.desiredClock)]
self._adb.shell('''echo 1 > /sys/devices/system/cpu/cpu{id}/online
echo userspace > /sys/devices/system/cpu/cpu{id}/cpufreq/scaling_governor
echo {speed} > /sys/devices/system/cpu/cpu{id}/cpufreq/scaling_max_freq
echo {speed} > /sys/devices/system/cpu/cpu{id}/cpufreq/scaling_min_freq
echo {speed} > /sys/devices/system/cpu/cpu{id}/cpufreq/scaling_setspeed'''.format(id=i, speed=speed))
def lock_adreno_gpu(self):
# Use presence of /sys/class/kgsl to indicate Adreno GPU
exists = self._adb.check('test -d /sys/class/kgsl && echo y')
if (exists.strip() != 'y'):
print('Not attempting Adreno GPU clock locking steps')
return
# variance reducing changes
self._adb.shell('''
echo 0 > /sys/class/kgsl/kgsl-3d0/bus_split
echo 1 > /sys/class/kgsl/kgsl-3d0/force_clk_on
echo 10000 > /sys/class/kgsl/kgsl-3d0/idle_timer''')
freqs = self._adb.check('cat /sys/class/kgsl/kgsl-3d0/devfreq/available_frequencies').split()
speed = freqs[int((len(freqs)-1) * self.desiredClock)]
# Set GPU to performance mode and lock clock
self._adb.shell('''
echo performance > /sys/class/kgsl/kgsl-3d0/devfreq/governor
echo {speed} > /sys/class/kgsl/kgsl-3d0/devfreq/max_freq
echo {speed} > /sys/class/kgsl/kgsl-3d0/devfreq/min_freq'''.format(speed=speed))
# Set GPU power level
self._adb.shell('''
echo 1 > /sys/class/kgsl/kgsl-3d0/max_pwrlevel
echo 1 > /sys/class/kgsl/kgsl-3d0/min_pwrlevel''')

View File

@ -73,6 +73,11 @@ __argparse.add_argument('-a', '--resultsfile',
help="optional file to append results into")
__argparse.add_argument('--ddl',
action='store_true', help="record the skp into DDLs before rendering")
__argparse.add_argument('--lock-clocks',
action='store_true', help="Put device in benchmarking mode (locked clocks, no other processes)")
__argparse.add_argument('--clock-speed',
type=float, default=66.0, help="A number between 0 and 100 indicating how fast to lock the CPU and GPU clock."
"Valid speeds are chosen from their respective available frequencies list.")
__argparse.add_argument('--ddlNumRecordingThreads',
type=int, default=0,
help="number of DDL recording threads (0=num_cores)")
@ -340,9 +345,12 @@ def main():
srcs = _path.find_skps(FLAGS.srcs)
assert srcs
if FLAGS.adb:
adb = Adb(FLAGS.device_serial, FLAGS.adb_binary,
echo=(FLAGS.verbosity >= 5))
from _hardware_android import HardwareAndroid
model = adb.check('getprop ro.product.model').strip()
if model == 'Pixel C':
from _hardware_pixel_c import HardwarePixelC
@ -357,10 +365,17 @@ def main():
from _hardware_nexus_6p import HardwareNexus6P
hardware = HardwareNexus6P(adb)
else:
from _hardware_android import HardwareAndroid
print("WARNING: %s: don't know how to monitor this hardware; results "
"may be unreliable." % model, file=sys.stderr)
hardware = HardwareAndroid(adb)
if FLAGS.lock_clocks:
hardware.__enter__()
print("Entered benchmarking mode, not running benchmarks. Reboot to restore.");
return;
if FLAGS.clock_speed:
hardware.setDesiredClock(FLAGS.clock_speed)
else:
hardware = Hardware()