diff options
author | epenner@chromium.org <epenner@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-06-20 22:33:25 +0000 |
---|---|---|
committer | epenner@chromium.org <epenner@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-06-20 22:33:25 +0000 |
commit | b51cfab22d3a5f2c175f56a1d20a557644aa1297 (patch) | |
tree | 6fbd143526482402f99aedb686a3203aff6ad68b /build | |
parent | d6a845e8e82060ee7e757bdde46e9c681a46c318 (diff) | |
download | chromium_src-b51cfab22d3a5f2c175f56a1d20a557644aa1297.zip chromium_src-b51cfab22d3a5f2c175f56a1d20a557644aa1297.tar.gz chromium_src-b51cfab22d3a5f2c175f56a1d20a557644aa1297.tar.bz2 |
Telemetry: Set scaling governor on all cpus (on all devices)
We try to set the scaling governor for all CPU cores, but
this doesn't work SOCs that dynamically disable cores
entirely (ie. Qualcomm). Since this only happens on Qcomm,
this patch stops the 'mpdecision' process on Qualcomm, which
makes it behave like other devices.
PERF-SHERIFFS: This may improve metrics for the better given
all cores are in 'performance' mode now. It should hopefully
reduce noise, since a different number of cores might have
had 'performance' set on each run, and any code that runs on
a non-performance core will suffer from noisy timings/rates.
Example: Tough-compositor-cases std-dev went from 0.25ms to
0.04ms with this change.
BUG=383566
Review URL: https://codereview.chromium.org/338233003
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@278837 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'build')
-rw-r--r-- | build/android/pylib/gtest/test_runner.py | 2 | ||||
-rw-r--r-- | build/android/pylib/perf/perf_control.py | 91 | ||||
-rw-r--r-- | build/android/pylib/perf/perf_control_unittest.py | 23 |
3 files changed, 62 insertions, 54 deletions
diff --git a/build/android/pylib/gtest/test_runner.py b/build/android/pylib/gtest/test_runner.py index dd09488..cea7992 100644 --- a/build/android/pylib/gtest/test_runner.py +++ b/build/android/pylib/gtest/test_runner.py @@ -192,7 +192,7 @@ class TestRunner(base_test_runner.BaseTestRunner): def TearDown(self): """Cleans up the test enviroment for the test suite.""" if _TestSuiteRequiresHighPerfMode(self.test_package.suite_name): - self._perf_controller.RestoreOriginalPerfMode() + self._perf_controller.SetDefaultPerfMode() self.test_package.ClearApplicationState(self.device) self.tool.CleanUpEnvironment() super(TestRunner, self).TearDown() diff --git a/build/android/pylib/perf/perf_control.py b/build/android/pylib/perf/perf_control.py index 1c88945..e13c02a 100644 --- a/build/android/pylib/perf/perf_control.py +++ b/build/android/pylib/perf/perf_control.py @@ -13,6 +13,7 @@ class PerfControl(object): """Provides methods for setting the performance mode of a device.""" _SCALING_GOVERNOR_FMT = ( '/sys/devices/system/cpu/cpu%d/cpufreq/scaling_governor') + _CPU_ONLINE_FMT = '/sys/devices/system/cpu/cpu%d/online' _KERNEL_MAX = '/sys/devices/system/cpu/kernel_max' def __init__(self, device): @@ -25,13 +26,22 @@ class PerfControl(object): assert kernel_max, 'Unable to find %s' % PerfControl._KERNEL_MAX self._kernel_max = int(kernel_max[0]) logging.info('Maximum CPU index: %d', self._kernel_max) - self._original_scaling_governor = \ - self._device.old_interface.GetFileContents( - PerfControl._SCALING_GOVERNOR_FMT % 0, - log_result=False)[0] + self._have_mpdecision = self._device.old_interface.FileExistsOnDevice( + '/system/bin/mpdecision') + + @property + def _NumCpuCores(self): + return self._kernel_max + 1 def SetHighPerfMode(self): + # TODO(epenner): Enable on all devices (http://crbug.com/383566) + if 'Nexus 4' == self._device.old_interface.GetProductModel(): + self._ForceAllCpusOnline(True) + self._SetScalingGovernorInternal('performance') + + def SetPerfProfilingMode(self): """Sets the highest possible performance mode for the device.""" + self._ForceAllCpusOnline(True) self._SetScalingGovernorInternal('performance') def SetDefaultPerfMode(self): @@ -45,13 +55,10 @@ class PerfControl(object): 'Nexus 10': 'interactive' }.get(product_model, 'ondemand') self._SetScalingGovernorInternal(governor_mode) - - def RestoreOriginalPerfMode(self): - """Resets the original performance mode of the device.""" - self._SetScalingGovernorInternal(self._original_scaling_governor) + self._ForceAllCpusOnline(False) def _SetScalingGovernorInternal(self, value): - for cpu in range(self._kernel_max + 1): + for cpu in range(self._NumCpuCores): scaling_governor_file = PerfControl._SCALING_GOVERNOR_FMT % cpu if self._device.old_interface.FileExistsOnDevice(scaling_governor_file): logging.info('Writing scaling governor mode \'%s\' -> %s', @@ -59,37 +66,43 @@ class PerfControl(object): self._device.old_interface.SetProtectedFileContents( scaling_governor_file, value) - def ForceAllCpusOnline(self, force_online): - """Force all CPUs on a device to be online. + def _AllCpusAreOnline(self): + for cpu in range(self._NumCpuCores): + online_path = PerfControl._CPU_ONLINE_FMT % cpu + if self._device.old_interface.GetFileContents(online_path)[0] == '0': + return False + return True + + def _ForceAllCpusOnline(self, force_online): + """Enable all CPUs on a device. - Force every CPU core on an Android device to remain online, or return the - cores under system power management control. This is needed to work around - a bug in perf which makes it unable to record samples from CPUs that become - online when recording is already underway. + Some vendors (or only Qualcomm?) hot-plug their CPUs, which can add noise + to measurements: + - In perf, samples are only taken for the CPUs that are online when the + measurement is started. + - The scaling governor can't be set for an offline CPU and frequency scaling + on newly enabled CPUs adds noise to both perf and tracing measurements. + + It appears Qualcomm is the only vendor that hot-plugs CPUs, and on Qualcomm + this is done by "mpdecision". - Args: - force_online: True to set all CPUs online, False to return them under - system power management control. """ - def ForceCpuOnline(online_path): - script = 'chmod 644 {0}; echo 1 > {0}; chmod 444 {0}'.format(online_path) + if self._have_mpdecision: + script = 'stop mpdecision' if force_online else 'start mpdecision' self._device.RunShellCommand(script, root=True) - return self._device.old_interface.GetFileContents(online_path)[0] == '1' - - def ResetCpu(online_path): - self._device.RunShellCommand('chmod 644 %s' % online_path, root=True) - - def WaitFor(condition): - for _ in range(100): - if condition(): - return - time.sleep(0.1) - raise RuntimeError('Timed out') - - cpu_online_files = self._device.RunShellCommand( - 'ls -d /sys/devices/system/cpu/cpu[0-9]*/online') - for online_path in cpu_online_files: - if force_online: - WaitFor(lambda: ForceCpuOnline(online_path)) - else: - ResetCpu(online_path) + + if not self._have_mpdecision and not self._AllCpusAreOnline(): + logging.warning('Unexpected cpu hot plugging detected.') + + if not force_online: + return + + for cpu in range(self._NumCpuCores): + online_path = PerfControl._CPU_ONLINE_FMT % cpu + self._device.old_interface.SetProtectedFileContents( + online_path, '1') + + # Double check all cores stayed online. + time.sleep(0.25) + if not self._AllCpusAreOnline(): + raise RuntimeError('Failed to force CPUs online') diff --git a/build/android/pylib/perf/perf_control_unittest.py b/build/android/pylib/perf/perf_control_unittest.py index a83b482..7bdc962 100644 --- a/build/android/pylib/perf/perf_control_unittest.py +++ b/build/android/pylib/perf/perf_control_unittest.py @@ -1,6 +1,7 @@ # Copyright 2014 The Chromium Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +# pylint: disable=W0212 import os import sys @@ -12,7 +13,6 @@ from pylib import android_commands from pylib.device import device_utils from pylib.perf import perf_control - class TestPerfControl(unittest.TestCase): def setUp(self): if not os.getenv('BUILDTYPE'): @@ -23,24 +23,19 @@ class TestPerfControl(unittest.TestCase): self._device = device_utils.DeviceUtils( android_commands.AndroidCommands(device=devices[0])) - def testForceAllCpusOnline(self): + def testHighPerfMode(self): perf = perf_control.PerfControl(self._device) - cpu_online_files = self._device.RunShellCommand( - 'ls -d /sys/devices/system/cpu/cpu[0-9]*/online') try: - perf.ForceAllCpusOnline(True) - for path in cpu_online_files: + perf.SetPerfProfilingMode() + for cpu in range(perf._NumCpuCores): + path = perf_control.PerfControl._CPU_ONLINE_FMT % cpu self.assertEquals('1', self._device.old_interface.GetFileContents(path)[0]) - mode = self._device.RunShellCommand('ls -l %s' % path)[0] - self.assertEquals('-r--r--r--', mode[:10]) + path = perf_control.PerfControl._SCALING_GOVERNOR_FMT % cpu + self.assertEquals('performance', + self._device.old_interface.GetFileContents(path)[0]) finally: - perf.ForceAllCpusOnline(False) - - for path in cpu_online_files: - mode = self._device.RunShellCommand('ls -l %s' % path)[0] - self.assertEquals('-rw-r--r--', mode[:10]) - + perf.SetDefaultPerfMode() if __name__ == '__main__': unittest.main() |