summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--build/android/pylib/gtest/test_runner.py2
-rw-r--r--build/android/pylib/perf/perf_control.py91
-rw-r--r--build/android/pylib/perf/perf_control_unittest.py23
-rw-r--r--tools/android/adb_profile_chrome/perf_controller.py4
-rw-r--r--tools/telemetry/telemetry/core/platform/profiler/perf_profiler.py6
5 files changed, 67 insertions, 59 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()
diff --git a/tools/android/adb_profile_chrome/perf_controller.py b/tools/android/adb_profile_chrome/perf_controller.py
index 523fb85..aeb29fd 100644
--- a/tools/android/adb_profile_chrome/perf_controller.py
+++ b/tools/android/adb_profile_chrome/perf_controller.py
@@ -58,7 +58,7 @@ class _PerfProfiler(object):
if categories:
cmd += ['--event', ','.join(categories)]
self._perf_control = perf_control.PerfControl(self._device)
- self._perf_control.ForceAllCpusOnline(True)
+ self._perf_control.SetPerfProfilingMode()
self._perf_process = subprocess.Popen(cmd,
stdout=self._log_file,
stderr=subprocess.STDOUT)
@@ -67,7 +67,7 @@ class _PerfProfiler(object):
perf_pids = self._device.old_interface.ExtractPid('perf')
self._device.RunShellCommand('kill -SIGINT ' + ' '.join(perf_pids))
self._perf_process.wait()
- self._perf_control.ForceAllCpusOnline(False)
+ self._perf_control.SetDefaultPerfMode()
def _FailWithLog(self, msg):
self._log_file.seek(0)
diff --git a/tools/telemetry/telemetry/core/platform/profiler/perf_profiler.py b/tools/telemetry/telemetry/core/platform/profiler/perf_profiler.py
index 6b460d9..139cd37 100644
--- a/tools/telemetry/telemetry/core/platform/profiler/perf_profiler.py
+++ b/tools/telemetry/telemetry/core/platform/profiler/perf_profiler.py
@@ -172,7 +172,7 @@ class PerfProfiler(profiler.Profiler):
device = browser_backend.adb.device()
perf_binary = android_profiling_helper.PrepareDeviceForPerf(device)
self._perf_control = perf_control.PerfControl(device)
- self._perf_control.ForceAllCpusOnline(True)
+ self._perf_control.SetPerfProfilingMode()
else:
_PrepareHostForPerf()
@@ -185,7 +185,7 @@ class PerfProfiler(profiler.Profiler):
perf_binary, perfhost_binary))
except:
if self._is_android:
- self._perf_control.ForceAllCpusOnline(False)
+ self._perf_control.SetDefaultPerfMode()
raise
@classmethod
@@ -209,7 +209,7 @@ class PerfProfiler(profiler.Profiler):
def CollectProfile(self):
if self._is_android:
- self._perf_control.ForceAllCpusOnline(False)
+ self._perf_control.SetDefaultPerfMode()
output_files = []
for single_process in self._process_profilers:
output_files.append(single_process.CollectProfile())