aboutsummaryrefslogtreecommitdiff
path: root/catapult/devil/devil/android/perf/perf_control.py
diff options
context:
space:
mode:
Diffstat (limited to 'catapult/devil/devil/android/perf/perf_control.py')
-rw-r--r--catapult/devil/devil/android/perf/perf_control.py267
1 files changed, 167 insertions, 100 deletions
diff --git a/catapult/devil/devil/android/perf/perf_control.py b/catapult/devil/devil/android/perf/perf_control.py
index 1226be80..59485e0e 100644
--- a/catapult/devil/devil/android/perf/perf_control.py
+++ b/catapult/devil/devil/android/perf/perf_control.py
@@ -11,7 +11,6 @@ from devil.android import device_errors
logger = logging.getLogger(__name__)
_atexit_messages = set()
-
# Defines how to switch between the default performance configuration
# ('default_mode') and the mode for use when benchmarking ('high_perf_mode').
# For devices not in the list the defaults are to set up the scaling governor to
@@ -24,93 +23,138 @@ _atexit_messages = set()
# TODO(crbug.com/383566): Add definitions for all devices used in the perf
# waterfall.
_PERFORMANCE_MODE_DEFINITIONS = {
- # Fire TV Edition - 4K
- 'AFTKMST12': {
- 'default_mode_governor': 'interactive',
- },
- # Pixel 3
- 'blueline': {
- 'high_perf_mode': {
- 'bring_cpu_cores_online': True,
- # The SoC is Arm big.LITTLE. The cores 0..3 are LITTLE, the 4..7 are big.
- 'cpu_max_freq': {'0..3': 1228800, '4..7': 1536000},
- 'gpu_max_freq': 520000000,
- },
- 'default_mode': {
- 'cpu_max_freq': {'0..3': 1766400, '4..7': 2649600},
- 'gpu_max_freq': 710000000,
- },
- 'default_mode_governor': 'schedutil',
- },
- 'GT-I9300': {
- 'default_mode_governor': 'pegasusq',
- },
- 'Galaxy Nexus': {
- 'default_mode_governor': 'interactive',
- },
- # Pixel
- 'msm8996': {
- 'high_perf_mode': {
- 'bring_cpu_cores_online': True,
- 'cpu_max_freq': 1209600,
- 'gpu_max_freq': 315000000,
- },
- 'default_mode': {
- # The SoC is Arm big.LITTLE. The cores 0..1 are LITTLE, the 2..3 are big.
- 'cpu_max_freq': {'0..1': 1593600, '2..3': 2150400},
- 'gpu_max_freq': 624000000,
- },
- 'default_mode_governor': 'sched',
- },
- 'Nexus 7': {
- 'default_mode_governor': 'interactive',
- },
- 'Nexus 10': {
- 'default_mode_governor': 'interactive',
- },
- 'Nexus 4': {
- 'high_perf_mode': {
- 'bring_cpu_cores_online': True,
+ # Fire TV Edition - 4K
+ 'AFTKMST12': {
+ 'default_mode_governor': 'interactive',
+ },
+ # Pixel 3
+ 'blueline': {
+ 'high_perf_mode': {
+ 'bring_cpu_cores_online': True,
+ # The SoC is Arm big.LITTLE. The cores 0..3 are LITTLE,
+ # the 4..7 are big.
+ 'cpu_max_freq': {
+ '0..3': 1228800,
+ '4..7': 1536000
+ },
+ 'gpu_max_freq': 520000000,
+ },
+ 'default_mode': {
+ 'cpu_max_freq': {
+ '0..3': 1766400,
+ '4..7': 2649600
+ },
+ 'gpu_max_freq': 710000000,
+ },
+ 'big_cores': ['4', '5', '6', '7'],
+ 'default_mode_governor': 'schedutil',
+ },
+ 'Pixel 2': {
+ 'high_perf_mode': {
+ 'bring_cpu_cores_online': True,
+ # These are set to roughly 7/8 of the max frequency. The purpose of
+ # this is to ensure that thermal throttling doesn't kick in midway
+ # through a test and cause flaky results. It should also improve the
+ # longevity of the devices by keeping them cooler.
+ 'cpu_max_freq': {
+ '0..3': 1670400,
+ '4..7': 2208000,
+ },
+ 'gpu_max_freq': 670000000,
+ },
+ 'default_mode': {
+ # These are the maximum frequencies available for these CPUs and
+ # GPUs.
+ 'cpu_max_freq': {
+ '0..3': 1900800,
+ '4..7': 2457600,
+ },
+ 'gpu_max_freq': 710000000,
+ },
+ 'big_cores': ['4', '5', '6', '7'],
+ 'default_mode_governor': 'schedutil',
+ },
+ 'GT-I9300': {
+ 'default_mode_governor': 'pegasusq',
+ },
+ 'Galaxy Nexus': {
+ 'default_mode_governor': 'interactive',
+ },
+ # Pixel
+ 'msm8996': {
+ 'high_perf_mode': {
+ 'bring_cpu_cores_online': True,
+ 'cpu_max_freq': 1209600,
+ 'gpu_max_freq': 315000000,
+ },
+ 'default_mode': {
+ # The SoC is Arm big.LITTLE. The cores 0..1 are LITTLE,
+ # the 2..3 are big.
+ 'cpu_max_freq': {
+ '0..1': 1593600,
+ '2..3': 2150400
+ },
+ 'gpu_max_freq': 624000000,
+ },
+ 'big_cores': ['2', '3'],
+ 'default_mode_governor': 'sched',
},
- 'default_mode_governor': 'ondemand',
- },
- 'Nexus 5': {
- # The list of possible GPU frequency values can be found in:
- # /sys/class/kgsl/kgsl-3d0/gpu_available_frequencies.
- # For CPU cores the possible frequency values are at:
- # /sys/devices/system/cpu/cpu0/cpufreq/scaling_available_frequencies
- 'high_perf_mode': {
- 'bring_cpu_cores_online': True,
- 'cpu_max_freq': 1190400,
- 'gpu_max_freq': 200000000,
+ 'Nexus 7': {
+ 'default_mode_governor': 'interactive',
},
- 'default_mode': {
- 'cpu_max_freq': 2265600,
- 'gpu_max_freq': 450000000,
+ 'Nexus 10': {
+ 'default_mode_governor': 'interactive',
},
- 'default_mode_governor': 'ondemand',
- },
- 'Nexus 5X': {
- 'high_perf_mode': {
- 'bring_cpu_cores_online': True,
- 'cpu_max_freq': 1248000,
- 'gpu_max_freq': 300000000,
+ 'Nexus 4': {
+ 'high_perf_mode': {
+ 'bring_cpu_cores_online': True,
+ },
+ 'default_mode_governor': 'ondemand',
},
- 'default_mode': {
- 'governor': 'ondemand',
- # The SoC is ARM big.LITTLE. The cores 4..5 are big, the 0..3 are LITTLE.
- 'cpu_max_freq': {'0..3': 1440000, '4..5': 1824000},
- 'gpu_max_freq': 600000000,
+ 'Nexus 5': {
+ # The list of possible GPU frequency values can be found in:
+ # /sys/class/kgsl/kgsl-3d0/gpu_available_frequencies.
+ # For CPU cores the possible frequency values are at:
+ # /sys/devices/system/cpu/cpu0/cpufreq/scaling_available_frequencies
+ 'high_perf_mode': {
+ 'bring_cpu_cores_online': True,
+ 'cpu_max_freq': 1190400,
+ 'gpu_max_freq': 200000000,
+ },
+ 'default_mode': {
+ 'cpu_max_freq': 2265600,
+ 'gpu_max_freq': 450000000,
+ },
+ 'default_mode_governor': 'ondemand',
+ },
+ 'Nexus 5X': {
+ 'high_perf_mode': {
+ 'bring_cpu_cores_online': True,
+ 'cpu_max_freq': 1248000,
+ 'gpu_max_freq': 300000000,
+ },
+ 'default_mode': {
+ 'governor': 'ondemand',
+ # The SoC is ARM big.LITTLE. The cores 4..5 are big,
+ # the 0..3 are LITTLE.
+ 'cpu_max_freq': {
+ '0..3': 1440000,
+ '4..5': 1824000
+ },
+ 'gpu_max_freq': 600000000,
+ },
+ 'big_cores': ['4', '5'],
+ 'default_mode_governor': 'ondemand',
},
- 'default_mode_governor': 'ondemand',
- },
}
+
def _GetPerfModeDefinitions(product_model):
if product_model.startswith('AOSP on '):
product_model = product_model.replace('AOSP on ', '')
return _PERFORMANCE_MODE_DEFINITIONS.get(product_model)
+
def _NoisyWarning(message):
message += ' Results may be NOISY!!'
logger.warning(message)
@@ -144,7 +188,8 @@ class PerfControl(object):
raw = self._ReadEachCpuFile(self._AVAILABLE_GOVERNORS_REL_PATH)
self._available_governors = [
(cpu, raw_governors.strip().split() if not exit_code else None)
- for cpu, raw_governors, exit_code in raw]
+ for cpu, raw_governors, exit_code in raw
+ ]
def _SetMaxFrequenciesFromMode(self, mode):
"""Set maximum frequencies for GPU and CPU cores.
@@ -165,8 +210,9 @@ class PerfControl(object):
range_min, range_max = int(range_min), int(range_max)
else:
range_min = range_max = int(key)
- cpu_files = ['cpu%d' % number
- for number in xrange(range_min, range_max + 1)]
+ cpu_files = [
+ 'cpu%d' % number for number in xrange(range_min, range_max + 1)
+ ]
# Set the |max_frequency| on requested subset of the cores.
self._SetScalingMaxFreqForCpus(max_frequency, ' '.join(cpu_files))
gpu_max_freq = mode.get('gpu_max_freq')
@@ -197,6 +243,25 @@ class PerfControl(object):
self.SetScalingGovernor('performance')
self._SetMaxFrequenciesFromMode(high_perf_mode)
+ def SetLittleOnlyMode(self):
+ """Turns off big CPU cores on the device."""
+ try:
+ self._device.EnableRoot()
+ except device_errors.CommandFailedError:
+ _NoisyWarning('Need root to turn off cores.')
+ return
+ mode_definitions = _GetPerfModeDefinitions(self._device.product_model)
+ if not mode_definitions:
+ _NoisyWarning('Unknown device: %s. Can\'t turn off cores.'
+ % self._device.product_model)
+ return
+ big_cores = mode_definitions.get('big_cores', [])
+ if not big_cores:
+ _NoisyWarning('No mode definition for device: %s.' %
+ self._device.product_model)
+ return
+ self._ForceCpusOffline(cpu_list=big_cores)
+
def SetDefaultPerfMode(self):
"""Sets the performance mode for the device to its default mode."""
if not self._device.HasRoot():
@@ -207,7 +272,7 @@ class PerfControl(object):
else:
default_mode_governor = mode_definitions.get('default_mode_governor')
assert default_mode_governor, ('Default mode governor must be provided '
- 'for all perf mode definitions.')
+ 'for all perf mode definitions.')
self.SetScalingGovernor(default_mode_governor)
default_mode = mode_definitions.get('default_mode')
if default_mode:
@@ -226,9 +291,10 @@ class PerfControl(object):
def GetCpuInfo(self):
online = (output.rstrip() == '1' and status == 0
for (_, output, status) in self._ForEachCpu('cat "$CPU/online"'))
- governor = (output.rstrip() if status == 0 else None
- for (_, output, status)
- in self._ForEachCpu('cat "$CPU/cpufreq/scaling_governor"'))
+ governor = (
+ output.rstrip() if status == 0 else None
+ for (_, output,
+ status) in self._ForEachCpu('cat "$CPU/cpufreq/scaling_governor"'))
return zip(self._cpu_files, online, governor)
def _ForEachCpu(self, cmd, cpu_list=None):
@@ -249,9 +315,7 @@ class PerfControl(object):
cpu_list = self._cpu_file_list
script = '; '.join([
'for CPU in %s' % cpu_list,
- 'do %s' % cmd,
- 'echo -n "%~%$?%~%"',
- 'done'
+ 'do %s' % cmd, 'echo -n "%~%$?%~%"', 'done'
])
output = self._device.RunShellCommand(
script, cwd=self._CPU_PATH, check_return=True, as_root=True, shell=True)
@@ -273,8 +337,7 @@ class PerfControl(object):
self._ConditionallyWriteCpuFiles(path, value, cpu_files, condition='true')
def _ReadEachCpuFile(self, path):
- return self._ForEachCpu(
- 'cat "$CPU/{path}"'.format(path=path))
+ return self._ForEachCpu('cat "$CPU/{path}"'.format(path=path))
def SetScalingGovernor(self, value):
"""Sets the scaling governor to the given value on all possible CPUs.
@@ -286,10 +349,9 @@ class PerfControl(object):
value: [string] The new governor value.
"""
condition = 'test -e "{path}" && grep -q {value} {path}'.format(
- path=('${CPU}/%s' % self._AVAILABLE_GOVERNORS_REL_PATH),
- value=value)
- self._ConditionallyWriteCpuFiles(
- 'cpufreq/scaling_governor', value, self._cpu_file_list, condition)
+ path=('${CPU}/%s' % self._AVAILABLE_GOVERNORS_REL_PATH), value=value)
+ self._ConditionallyWriteCpuFiles('cpufreq/scaling_governor', value,
+ self._cpu_file_list, condition)
def GetScalingGovernor(self):
"""Gets the currently set governor for each CPU.
@@ -299,9 +361,8 @@ class PerfControl(object):
governor.
"""
raw = self._ReadEachCpuFile('cpufreq/scaling_governor')
- return [
- (cpu, raw_governor.strip() if not exit_code else None)
- for cpu, raw_governor, exit_code in raw]
+ return [(cpu, raw_governor.strip() if not exit_code else None)
+ for cpu, raw_governor, exit_code in raw]
def ListAvailableGovernors(self):
"""Returns the list of available governors for each CPU.
@@ -316,9 +377,8 @@ class PerfControl(object):
self._WriteCpuFiles('cpufreq/scaling_max_freq', '%d' % value, cpu_files)
def _SetMaxGpuClock(self, value):
- self._device.WriteFile('/sys/class/kgsl/kgsl-3d0/max_gpuclk',
- str(value),
- as_root=True)
+ self._device.WriteFile(
+ '/sys/class/kgsl/kgsl-3d0/max_gpuclk', str(value), as_root=True)
def _AllCpusAreOnline(self):
results = self._ForEachCpu('cat "$CPU/online"')
@@ -326,8 +386,7 @@ class PerfControl(object):
# is likely because on these devices it is impossible to bring the cpu0
# offline. Assuming the same for all devices until proven otherwise.
return all(output.rstrip() == '1' and status == 0
- for (cpu, output, status) in results
- if cpu != 'cpu0')
+ for (cpu, output, status) in results if cpu != 'cpu0')
def _ForceAllCpusOnline(self, force_online):
"""Enable all CPUs on a device.
@@ -352,3 +411,11 @@ class PerfControl(object):
if force_online:
self._ForEachCpu('echo 1 > "$CPU/online"')
+
+ def _ForceCpusOffline(self, cpu_list):
+ """Disable selected CPUs on a device."""
+ if self._have_mpdecision:
+ cmd = ['stop', 'mpdecision']
+ self._device.RunShellCommand(cmd, check_return=True, as_root=True)
+
+ self._ForEachCpu('echo 0 > "$CPU/online"', cpu_list=cpu_list)