1d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)# Copyright 2013 The Chromium Authors. All rights reserved. 2d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be 3d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)# found in the LICENSE file. 4d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 55f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)import atexit 6d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)import logging 7f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 8a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochfrom pylib import android_commands 9a02191e04bc25c4935f804f2c080ae28663d096dBen Murdochfrom pylib.device import device_utils 10d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 11d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles)class PerfControl(object): 12d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) """Provides methods for setting the performance mode of a device.""" 13d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) _SCALING_GOVERNOR_FMT = ( 14d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) '/sys/devices/system/cpu/cpu%d/cpufreq/scaling_governor') 156d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) _CPU_ONLINE_FMT = '/sys/devices/system/cpu/cpu%d/online' 16d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) _KERNEL_MAX = '/sys/devices/system/cpu/kernel_max' 17d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 18a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch def __init__(self, device): 19a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch # TODO(jbudorick) Remove once telemetry gets switched over. 20a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch if isinstance(device, android_commands.AndroidCommands): 21a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch device = device_utils.DeviceUtils(device) 22a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch self._device = device 23116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch cpu_files = self._device.RunShellCommand( 24116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 'ls -d /sys/devices/system/cpu/cpu[0-9]*') 25116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch self._num_cpu_cores = len(cpu_files) 26116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch assert self._num_cpu_cores > 0, 'Failed to detect CPUs.' 27116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch logging.info('Number of CPUs: %d', self._num_cpu_cores) 28116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch self._have_mpdecision = self._device.FileExists('/system/bin/mpdecision') 29d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 30d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) def SetHighPerfMode(self): 315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) """Sets the highest possible performance mode for the device.""" 325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if not self._device.old_interface.IsRootEnabled(): 335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) message = 'Need root for performance mode. Results may be NOISY!!' 345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) logging.warning(message) 355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) # Add an additional warning at exit, such that it's clear that any results 365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) # may be different/noisy (due to the lack of intended performance mode). 375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) atexit.register(logging.warning, message) 385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return 396d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) # TODO(epenner): Enable on all devices (http://crbug.com/383566) 406d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) if 'Nexus 4' == self._device.old_interface.GetProductModel(): 416d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) self._ForceAllCpusOnline(True) 42116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if not self._AllCpusAreOnline(): 435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) logging.warning('Failed to force CPUs online. Results may be NOISY!') 446d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) self._SetScalingGovernorInternal('performance') 456d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 466d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) def SetPerfProfilingMode(self): 475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) """Enables all cores for reliable perf profiling.""" 486d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) self._ForceAllCpusOnline(True) 49d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) self._SetScalingGovernorInternal('performance') 50116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if not self._AllCpusAreOnline(): 51116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch if not self._device.old_interface.IsRootEnabled(): 52116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch raise RuntimeError('Need root to force CPUs online.') 53116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch raise RuntimeError('Failed to force CPUs online.') 54d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 55d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) def SetDefaultPerfMode(self): 56d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) """Sets the performance mode for the device to its default mode.""" 575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if not self._device.old_interface.IsRootEnabled(): 585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) return 59116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch product_model = self._device.GetProp('ro.product.model') 60d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) governor_mode = { 61d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 'GT-I9300': 'pegasusq', 62d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 'Galaxy Nexus': 'interactive', 63d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 'Nexus 4': 'ondemand', 64d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 'Nexus 7': 'interactive', 65d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 'Nexus 10': 'interactive' 66d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) }.get(product_model, 'ondemand') 67d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) self._SetScalingGovernorInternal(governor_mode) 686d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) self._ForceAllCpusOnline(False) 69d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) 70d0247b1b59f9c528cb6df88b4f2b9afaf80d181eTorne (Richard Coles) def _SetScalingGovernorInternal(self, value): 711320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci cpu_cores = ' '.join([str(x) for x in range(self._num_cpu_cores)]) 721320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci script = ('for CPU in %s; do\n' 731320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci ' FILE="/sys/devices/system/cpu/cpu$CPU/cpufreq/scaling_governor"\n' 741320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci ' test -e $FILE && echo %s > $FILE\n' 751320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci 'done\n') % (cpu_cores, value) 761320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci logging.info('Setting scaling governor mode: %s', value) 771320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci self._device.RunShellCommand(script, as_root=True) 78a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch 796d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) def _AllCpusAreOnline(self): 801320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci for cpu in range(1, self._num_cpu_cores): 816d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) online_path = PerfControl._CPU_ONLINE_FMT % cpu 825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) # TODO(epenner): Investigate why file may be missing 835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) # (http://crbug.com/397118) 845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) if not self._device.FileExists(online_path) or \ 855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles) self._device.ReadFile(online_path)[0] == '0': 866d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) return False 876d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) return True 886d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 896d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) def _ForceAllCpusOnline(self, force_online): 906d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) """Enable all CPUs on a device. 91f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 926d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) Some vendors (or only Qualcomm?) hot-plug their CPUs, which can add noise 936d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) to measurements: 946d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) - In perf, samples are only taken for the CPUs that are online when the 956d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) measurement is started. 966d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) - The scaling governor can't be set for an offline CPU and frequency scaling 976d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) on newly enabled CPUs adds noise to both perf and tracing measurements. 986d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 996d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) It appears Qualcomm is the only vendor that hot-plugs CPUs, and on Qualcomm 1006d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) this is done by "mpdecision". 101f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 102f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) """ 1036d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) if self._have_mpdecision: 1046d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) script = 'stop mpdecision' if force_online else 'start mpdecision' 105116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch self._device.RunShellCommand(script, as_root=True) 1066d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 1076d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) if not self._have_mpdecision and not self._AllCpusAreOnline(): 1086d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) logging.warning('Unexpected cpu hot plugging detected.') 1096d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 1106d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) if not force_online: 1116d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) return 1126d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) 113116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch for cpu in range(self._num_cpu_cores): 1146d86b77056ed63eb6871182f42a9fd5f07550f90Torne (Richard Coles) online_path = PerfControl._CPU_ONLINE_FMT % cpu 115116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch self._device.WriteFile(online_path, '1', as_root=True) 116