Add Pixel C knobs to skpbench

BUG=skia:
GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2369533002

Review-Url: https://codereview.chromium.org/2369533002
This commit is contained in:
csmartdalton 2016-09-23 11:36:11 -07:00 committed by Commit bot
parent 68c3d30702
commit bf41fa841b
5 changed files with 170 additions and 15 deletions

View File

@ -3,7 +3,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
'''Parses an skpbench result from a line of output text.'''
"""Parses an skpbench result from a line of output text."""
from __future__ import print_function
import re

View File

@ -5,12 +5,21 @@
import time
class HardwareException(Exception):
def __init__(self, message, sleeptime=60):
Exception.__init__(self, message)
self.sleeptime = sleeptime
class Hardware:
"""Locks down and monitors hardware for benchmarking.
This is a common base for classes that can control the specific hardware
we are running on. Its purpose is to lock the hardware into a constant
benchmarking mode for the duration of a 'with' block. e.g.:
with hardware:
run_benchmark()
While benchmarking, the caller must call sanity_check() frequently to verify
the hardware state has not changed.
"""
def __init__(self):
self.kick_in_time = 0
@ -21,9 +30,60 @@ class Hardware:
pass
def sanity_check(self):
'''Raises a HardwareException if any hardware state is not as expected.'''
"""Raises a HardwareException if any hardware state is not as expected."""
pass
def sleep(self, sleeptime):
'''Puts the hardware into a resting state for a fixed amount of time.'''
"""Puts the hardware into a resting state for a fixed amount of time."""
time.sleep(sleeptime)
class HardwareException(Exception):
"""Gets thrown when certain hardware state is not what we expect.
Generally this happens because of thermal conditions or other variables beyond
our control, and the appropriate course of action is to take a short nap
before resuming the benchmark.
"""
def __init__(self, message, sleeptime=60):
Exception.__init__(self, message)
self.sleeptime = sleeptime
class Expectation:
"""Simple helper for checking the readings on hardware gauges."""
def __init__(self, value_type, min_value=None, max_value=None,
exact_value=None, name=None, sleeptime=60):
self.value_type = value_type
self.min_value = min_value
self.max_value = max_value
self.exact_value = exact_value
self.name = name
self.sleeptime = sleeptime
def check(self, stringvalue):
typedvalue = self.value_type(stringvalue)
if self.min_value is not None and typedvalue < self.min_value:
raise HardwareException("%s is too low (%s, min=%s)" %
(self.name, stringvalue, str(self.min_value)),
sleeptime=self.sleeptime)
if self.max_value is not None and typedvalue > self.max_value:
raise HardwareException("%s is too high (%s, max=%s)" %
(self.name, stringvalue, str(self.max_value)),
sleeptime=self.sleeptime)
if self.exact_value is not None and typedvalue != self.exact_value:
raise HardwareException("unexpected %s (%s, expected=%s)" %
(self.name, stringvalue, str(self.exact_value)),
sleeptime=self.sleeptime)
@staticmethod
def check_all(expectations, stringvalues):
if len(stringvalues) != len(expectations):
raise Exception("unexpected reading from hardware gauges "
"(expected %i values):\n%s" %
(len(expectations), '\n'.join(stringvalues)))
for value, expected in zip(stringvalues, expectations):
expected.check(value)

View File

@ -0,0 +1,94 @@
# Copyright 2016 Google Inc.
#
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
from _hardware import HardwareException, Expectation
from _hardware_android import HardwareAndroid
CPU_CLOCK_RATE = 1836000
GPU_EMC_PROFILE = '0c: core 921 MHz emc 1600 MHz a A d D *'
GPU_EMC_PROFILE_ID = '0c'
class HardwarePixelC(HardwareAndroid):
def __init__(self, adb):
HardwareAndroid.__init__(self, adb)
def __enter__(self):
self._lock_clocks()
return HardwareAndroid.__enter__(self)
def __exit__(self, exception_type, exception_value, exception_traceback):
HardwareAndroid.__exit__(self, exception_type,
exception_value, exception_traceback)
self._unlock_clocks()
def _lock_clocks(self):
if not self._is_root:
return
# lock cpu clocks.
self._adb.shell('''\
for N in $(seq 0 3); do
echo userspace > /sys/devices/system/cpu/cpu$N/cpufreq/scaling_governor
echo %i > /sys/devices/system/cpu/cpu$N/cpufreq/scaling_setspeed
done''' % CPU_CLOCK_RATE)
# lock gpu/emc clocks.
self._adb.shell('''\
chown root:root /sys/devices/57000000.gpu/pstate
echo %s > /sys/devices/57000000.gpu/pstate''' % GPU_EMC_PROFILE_ID)
def _unlock_clocks(self):
if not self._is_root:
return
# unlock gpu/emc clocks.
self._adb.shell('''\
echo auto > /sys/devices/57000000.gpu/pstate
chown system:system /sys/devices/57000000.gpu/pstate''')
# unlock cpu clocks.
self._adb.shell('''\
for N in $(seq 0 3); do
echo 0 > /sys/devices/system/cpu/cpu$N/cpufreq/scaling_setspeed
echo interactive > /sys/devices/system/cpu/cpu$N/cpufreq/scaling_governor
done''')
def sanity_check(self):
HardwareAndroid.sanity_check(self)
if not self._is_root:
return
# only issue one shell command in an attempt to minimize interference.
result = self._adb.check_lines('''\
cat /sys/class/power_supply/bq27742-0/capacity \
/sys/class/thermal/thermal_zone7/temp \
/sys/class/thermal/thermal_zone0/temp \
/sys/class/thermal/thermal_zone1/temp \
/sys/class/thermal/thermal_zone7/cdev1/cur_state \
/sys/class/thermal/thermal_zone7/cdev0/cur_state
for N in $(seq 0 3); do
cat /sys/devices/system/cpu/cpu$N/cpufreq/scaling_cur_freq
done
cat /sys/devices/57000000.gpu/pstate | grep \*$''')
expectations = \
[Expectation(int, min_value=30, name='battery', sleeptime=30*60),
Expectation(int, max_value=40000, name='skin temperature'),
Expectation(int, max_value=86000, name='cpu temperature'),
Expectation(int, max_value=87000, name='gpu temperature'),
Expectation(int, exact_value=0, name='cpu throttle'),
Expectation(int, exact_value=0, name='gpu throttle')] + \
[Expectation(int, exact_value=CPU_CLOCK_RATE,
name='cpu_%i clock rate' % i, sleeptime=30)
for i in range(4)] + \
[Expectation(str, exact_value=GPU_EMC_PROFILE, name='gpu/emc profile')]
Expectation.check_all(expectations, result)
def sleep(self, sleeptime):
self._unlock_clocks()
HardwareAndroid.sleep(self, sleeptime)
self._lock_clocks()

View File

@ -18,7 +18,7 @@ import urllib
import urlparse
import webbrowser
__argparse = ArgumentParser(description='''
__argparse = ArgumentParser(description="""
Parses output files from skpbench.py into csv.
@ -31,7 +31,7 @@ This script can also be used to generate a Google sheet:
(3) Run parseskpbench.py with the --open flag.
''')
""")
__argparse.add_argument('-r', '--result',
choices=['median', 'accum', 'max', 'min'], default='median',

View File

@ -20,14 +20,14 @@ import subprocess
import sys
import time
__argparse = ArgumentParser(description='''
__argparse = ArgumentParser(description="""
Executes the skpbench binary with various configs and skps.
Also monitors the output in order to filter out and re-run results that have an
unacceptable stddev.
''')
""")
__argparse.add_argument('--adb',
action='store_true', help="execute skpbench over adb")
@ -82,7 +82,7 @@ class SubprocessMonitor(Thread):
Thread.__init__(self)
def run(self):
'''Runs on the background thread.'''
"""Runs on the background thread."""
for line in iter(self._proc.stdout.readline, b''):
self._queue.put(Message(Message.READLINE, line.decode('utf-8').rstrip()))
self._queue.put(Message(Message.EXIT))
@ -243,8 +243,9 @@ def main():
if FLAGS.adb:
adb = Adb(FLAGS.device_serial)
model = adb.get_device_model()
if False:
pass # TODO: unique subclasses tailored to individual platforms.
if model == 'Pixel C':
from _hardware_pixel_c import HardwarePixelC
hardware = HardwarePixelC(adb)
else:
from _hardware_android import HardwareAndroid
print("WARNING: %s: don't know how to monitor this hardware; results "