OLD | NEW |
1 # Copyright 2013 The Chromium Authors. All rights reserved. | 1 # Copyright 2013 The Chromium Authors. All rights reserved. |
2 # Use of this source code is governed by a BSD-style license that can be | 2 # Use of this source code is governed by a BSD-style license that can be |
3 # found in the LICENSE file. | 3 # found in the LICENSE file. |
4 | 4 |
5 import logging | 5 import logging |
6 import time | |
7 | 6 |
8 from pylib import android_commands | 7 from pylib import android_commands |
9 from pylib.device import device_utils | 8 from pylib.device import device_utils |
10 | 9 |
11 | 10 |
12 class PerfControl(object): | 11 class PerfControl(object): |
13 """Provides methods for setting the performance mode of a device.""" | 12 """Provides methods for setting the performance mode of a device.""" |
14 _SCALING_GOVERNOR_FMT = ( | 13 _SCALING_GOVERNOR_FMT = ( |
15 '/sys/devices/system/cpu/cpu%d/cpufreq/scaling_governor') | 14 '/sys/devices/system/cpu/cpu%d/cpufreq/scaling_governor') |
16 _CPU_ONLINE_FMT = '/sys/devices/system/cpu/cpu%d/online' | 15 _CPU_ONLINE_FMT = '/sys/devices/system/cpu/cpu%d/online' |
17 _KERNEL_MAX = '/sys/devices/system/cpu/kernel_max' | 16 _KERNEL_MAX = '/sys/devices/system/cpu/kernel_max' |
18 | 17 |
19 def __init__(self, device): | 18 def __init__(self, device): |
20 # TODO(jbudorick) Remove once telemetry gets switched over. | 19 # TODO(jbudorick) Remove once telemetry gets switched over. |
21 if isinstance(device, android_commands.AndroidCommands): | 20 if isinstance(device, android_commands.AndroidCommands): |
22 device = device_utils.DeviceUtils(device) | 21 device = device_utils.DeviceUtils(device) |
23 self._device = device | 22 self._device = device |
24 kernel_max = self._device.old_interface.GetFileContents( | 23 cpu_files = self._device.RunShellCommand( |
25 PerfControl._KERNEL_MAX, log_result=False) | 24 'ls -d /sys/devices/system/cpu/cpu[0-9]*') |
26 assert kernel_max, 'Unable to find %s' % PerfControl._KERNEL_MAX | 25 self._num_cpu_cores = len(cpu_files) |
27 self._kernel_max = int(kernel_max[0]) | 26 assert self._num_cpu_cores > 0, 'Failed to detect CPUs.' |
28 logging.info('Maximum CPU index: %d', self._kernel_max) | 27 logging.info('Number of CPUs: %d', self._num_cpu_cores) |
29 self._have_mpdecision = self._device.old_interface.FileExistsOnDevice( | 28 self._have_mpdecision = self._device.old_interface.FileExistsOnDevice( |
30 '/system/bin/mpdecision') | 29 '/system/bin/mpdecision') |
31 | 30 |
32 @property | |
33 def _NumCpuCores(self): | |
34 return self._kernel_max + 1 | |
35 | |
36 def SetHighPerfMode(self): | 31 def SetHighPerfMode(self): |
37 # TODO(epenner): Enable on all devices (http://crbug.com/383566) | 32 # TODO(epenner): Enable on all devices (http://crbug.com/383566) |
38 if 'Nexus 4' == self._device.old_interface.GetProductModel(): | 33 if 'Nexus 4' == self._device.old_interface.GetProductModel(): |
39 self._ForceAllCpusOnline(True) | 34 self._ForceAllCpusOnline(True) |
| 35 if not self._AllCpusAreOnline(): |
| 36 logging.warning('Failed to force CPUs online. Results may be noisy!') |
40 self._SetScalingGovernorInternal('performance') | 37 self._SetScalingGovernorInternal('performance') |
41 | 38 |
42 def SetPerfProfilingMode(self): | 39 def SetPerfProfilingMode(self): |
43 """Sets the highest possible performance mode for the device.""" | 40 """Sets the highest possible performance mode for the device.""" |
44 self._ForceAllCpusOnline(True) | 41 self._ForceAllCpusOnline(True) |
45 self._SetScalingGovernorInternal('performance') | 42 self._SetScalingGovernorInternal('performance') |
| 43 if not self._AllCpusAreOnline(): |
| 44 if not self._device.old_interface.IsRootEnabled(): |
| 45 raise RuntimeError('Need root to force CPUs online.') |
| 46 raise RuntimeError('Failed to force CPUs online.') |
46 | 47 |
47 def SetDefaultPerfMode(self): | 48 def SetDefaultPerfMode(self): |
48 """Sets the performance mode for the device to its default mode.""" | 49 """Sets the performance mode for the device to its default mode.""" |
49 product_model = self._device.old_interface.GetProductModel() | 50 product_model = self._device.old_interface.GetProductModel() |
50 governor_mode = { | 51 governor_mode = { |
51 'GT-I9300': 'pegasusq', | 52 'GT-I9300': 'pegasusq', |
52 'Galaxy Nexus': 'interactive', | 53 'Galaxy Nexus': 'interactive', |
53 'Nexus 4': 'ondemand', | 54 'Nexus 4': 'ondemand', |
54 'Nexus 7': 'interactive', | 55 'Nexus 7': 'interactive', |
55 'Nexus 10': 'interactive' | 56 'Nexus 10': 'interactive' |
56 }.get(product_model, 'ondemand') | 57 }.get(product_model, 'ondemand') |
57 self._SetScalingGovernorInternal(governor_mode) | 58 self._SetScalingGovernorInternal(governor_mode) |
58 self._ForceAllCpusOnline(False) | 59 self._ForceAllCpusOnline(False) |
59 | 60 |
60 def _SetScalingGovernorInternal(self, value): | 61 def _SetScalingGovernorInternal(self, value): |
61 for cpu in range(self._NumCpuCores): | 62 for cpu in range(self._num_cpu_cores): |
62 scaling_governor_file = PerfControl._SCALING_GOVERNOR_FMT % cpu | 63 scaling_governor_file = PerfControl._SCALING_GOVERNOR_FMT % cpu |
63 if self._device.old_interface.FileExistsOnDevice(scaling_governor_file): | 64 if self._device.old_interface.FileExistsOnDevice(scaling_governor_file): |
64 logging.info('Writing scaling governor mode \'%s\' -> %s', | 65 logging.info('Writing scaling governor mode \'%s\' -> %s', |
65 value, scaling_governor_file) | 66 value, scaling_governor_file) |
66 self._device.old_interface.SetProtectedFileContents( | 67 self._device.old_interface.SetProtectedFileContents( |
67 scaling_governor_file, value) | 68 scaling_governor_file, value) |
68 | 69 |
69 def _AllCpusAreOnline(self): | 70 def _AllCpusAreOnline(self): |
70 for cpu in range(self._NumCpuCores): | 71 for cpu in range(self._num_cpu_cores): |
71 online_path = PerfControl._CPU_ONLINE_FMT % cpu | 72 online_path = PerfControl._CPU_ONLINE_FMT % cpu |
72 if self._device.old_interface.GetFileContents(online_path)[0] == '0': | 73 if self._device.old_interface.GetFileContents(online_path)[0] == '0': |
73 return False | 74 return False |
74 return True | 75 return True |
75 | 76 |
76 def _ForceAllCpusOnline(self, force_online): | 77 def _ForceAllCpusOnline(self, force_online): |
77 """Enable all CPUs on a device. | 78 """Enable all CPUs on a device. |
78 | 79 |
79 Some vendors (or only Qualcomm?) hot-plug their CPUs, which can add noise | 80 Some vendors (or only Qualcomm?) hot-plug their CPUs, which can add noise |
80 to measurements: | 81 to measurements: |
81 - In perf, samples are only taken for the CPUs that are online when the | 82 - In perf, samples are only taken for the CPUs that are online when the |
82 measurement is started. | 83 measurement is started. |
83 - The scaling governor can't be set for an offline CPU and frequency scaling | 84 - The scaling governor can't be set for an offline CPU and frequency scaling |
84 on newly enabled CPUs adds noise to both perf and tracing measurements. | 85 on newly enabled CPUs adds noise to both perf and tracing measurements. |
85 | 86 |
86 It appears Qualcomm is the only vendor that hot-plugs CPUs, and on Qualcomm | 87 It appears Qualcomm is the only vendor that hot-plugs CPUs, and on Qualcomm |
87 this is done by "mpdecision". | 88 this is done by "mpdecision". |
88 | 89 |
89 """ | 90 """ |
90 if self._have_mpdecision: | 91 if self._have_mpdecision: |
91 script = 'stop mpdecision' if force_online else 'start mpdecision' | 92 script = 'stop mpdecision' if force_online else 'start mpdecision' |
92 self._device.RunShellCommand(script, root=True) | 93 self._device.RunShellCommand(script, root=True) |
93 | 94 |
94 if not self._have_mpdecision and not self._AllCpusAreOnline(): | 95 if not self._have_mpdecision and not self._AllCpusAreOnline(): |
95 logging.warning('Unexpected cpu hot plugging detected.') | 96 logging.warning('Unexpected cpu hot plugging detected.') |
96 | 97 |
97 if not force_online: | 98 if not force_online: |
98 return | 99 return |
99 | 100 |
100 for cpu in range(self._NumCpuCores): | 101 for cpu in range(self._num_cpu_cores): |
101 online_path = PerfControl._CPU_ONLINE_FMT % cpu | 102 online_path = PerfControl._CPU_ONLINE_FMT % cpu |
102 self._device.old_interface.SetProtectedFileContents( | 103 self._device.old_interface.SetProtectedFileContents( |
103 online_path, '1') | 104 online_path, '1') |
104 | |
105 # Double check all cores stayed online. | |
106 time.sleep(0.25) | |
107 if not self._AllCpusAreOnline(): | |
108 raise RuntimeError('Failed to force CPUs online') | |
OLD | NEW |