Chromium Code Reviews| 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 | 5 |
| 6 import logging | 6 import logging |
| 7 import time | |
| 7 | 8 |
| 8 | 9 |
| 9 class PerfControl(object): | 10 class PerfControl(object): |
| 10 """Provides methods for setting the performance mode of a device.""" | 11 """Provides methods for setting the performance mode of a device.""" |
| 11 _SCALING_GOVERNOR_FMT = ( | 12 |
| 12 '/sys/devices/system/cpu/cpu%d/cpufreq/scaling_governor') | |
| 13 _KERNEL_MAX = '/sys/devices/system/cpu/kernel_max' | 13 _KERNEL_MAX = '/sys/devices/system/cpu/kernel_max' |
| 14 _CPU_DIR_FMT = '/sys/devices/system/cpu/cpu%d/' | |
| 15 _SCALING_GOVERNOR_FMT = _CPU_DIR_FMT + 'cpufreq/scaling_governor' | |
| 16 _CPU_ONLINE_FMT = _CPU_DIR_FMT + 'online' | |
| 17 _SCALING_FREQUENCY_STAT_NAMES = [ | |
| 18 'cpufreq/scaling_min_freq', | |
| 19 'cpufreq/scaling_max_freq', | |
| 20 'cpufreq/scaling_cur_freq', | |
| 21 ] | |
| 14 | 22 |
| 15 def __init__(self, adb): | 23 def __init__(self, adb): |
| 16 self._adb = adb | 24 self._adb = adb |
| 17 kernel_max = self._adb.GetFileContents(PerfControl._KERNEL_MAX, | 25 kernel_max = self._adb.GetFileContents(PerfControl._KERNEL_MAX, |
| 18 log_result=False) | 26 log_result=False) |
| 19 assert kernel_max, 'Unable to find %s' % PerfControl._KERNEL_MAX | 27 assert kernel_max, 'Unable to find %s' % PerfControl._KERNEL_MAX |
| 20 self._kernel_max = int(kernel_max[0]) | 28 self._kernel_max = int(kernel_max[0]) |
| 21 logging.info('Maximum CPU index: %d', self._kernel_max) | 29 logging.info('Maximum CPU index: %d', self._kernel_max) |
| 22 self._original_scaling_governor = self._adb.GetFileContents( | 30 self._original_scaling_governor = self._adb.GetFileContents( |
| 23 PerfControl._SCALING_GOVERNOR_FMT % 0, | 31 PerfControl._SCALING_GOVERNOR_FMT % 0, |
| 24 log_result=False)[0] | 32 log_result=False)[0] |
| 33 self._LogCurrentCpuFrequencyInfo() | |
| 34 | |
| 35 # Bring CPUs online/offline manually on some device types to reduce variance | |
| 36 # in performance measurements. Other device types are either hard to manage | |
| 37 # properly or we did not decide what settings look 'typical' for them. | |
| 38 # 'Galaxy Nexus' and 'Nexus 10' seem to use both cores all time without | |
| 39 # hotplugging them manually, but we still may need to manage their frequency | |
| 40 # later. TODO(pasko): manage Nexus 7 CPUs with PerfControl, v1 and v2 differ | |
| 41 # significantly. | |
| 42 # | |
| 43 # *Not managing* CPUs manually means that only a subset of CPU properties | |
| 44 # are updated (scaling governor only now) and only for those CPUs | |
| 45 # represented by sysfs at the moment (/sys/devices/system/cpu/cpuX/...) | |
| 46 self._manage_cpus_manually = False | |
| 47 cpu_indexes_to_manage_manually = { | |
| 48 'Nexus 4': [0, 1], | |
| 49 'Nexus 5': [0, 1], | |
| 50 } | |
| 51 device_model = self._adb.GetProductModel() | |
| 52 if device_model in cpu_indexes_to_manage_manually: | |
| 53 self._manage_cpus_manually = True | |
| 54 self._cpus_to_manage = cpu_indexes_to_manage_manually[device_model] | |
| 55 self._cpus_on_originally = [] | |
| 56 for cpu in xrange(self._kernel_max + 1): | |
| 57 if '1' in self._ReadProtectedFile(PerfControl._CPU_ONLINE_FMT % cpu): | |
| 58 self._cpus_on_originally.append(cpu) | |
| 59 | |
| 60 def _BringCpuOffline(self, cpu_index): | |
| 61 logging.info('Bringing CPU #%d offline.', cpu_index) | |
| 62 self._adb.SetProtectedFileContents( | |
| 63 PerfControl._CPU_ONLINE_FMT % cpu_index, '0') | |
| 64 | |
| 65 def _BringCpuOnline(self, cpu_index): | |
| 66 "Brings a CPU core online, waits for it to show up in sysfs." | |
| 67 | |
| 68 logging.info('Bringing CPU #%d online.' %cpu_index) | |
| 69 times_to_wait_left = 5 | |
| 70 cpu_online_file = PerfControl._CPU_ONLINE_FMT % cpu_index | |
| 71 while (True): | |
| 72 self._adb.SetProtectedFileContents(cpu_online_file, '1') | |
| 73 if '1' in self._ReadProtectedFile(cpu_online_file): | |
| 74 break | |
| 75 if times_to_wait_left == 0: | |
| 76 logging.warning('Gave up bringing CPU %d online', cpu_index) | |
| 77 break | |
| 78 times_to_wait_left -= 1 | |
| 79 logging.warning('Could not bring CPU %d online, retrying..', | |
| 80 cpu_index) | |
| 81 time.sleep(0.1) | |
| 82 | |
| 83 def _ReadProtectedFile(self, file_name): | |
| 84 return '\n'.join(self._adb.GetProtectedFileContents(file_name)) | |
| 85 | |
| 86 def _LogCurrentCpuFrequencyInfo(self): | |
| 87 for cpu in xrange(self._kernel_max + 1): | |
| 88 for stat_name in PerfControl._SCALING_FREQUENCY_STAT_NAMES: | |
| 89 stat_file_name = (PerfControl._CPU_DIR_FMT + stat_name) % cpu; | |
| 90 if self._adb.FileExistsOnDevice(stat_file_name): | |
| 91 info = self._ReadProtectedFile(stat_file_name) | |
| 92 logging.info('CPU #%d frequency info: %s: %s', cpu, stat_name, info) | |
| 25 | 93 |
| 26 def SetHighPerfMode(self): | 94 def SetHighPerfMode(self): |
| 27 """Sets the highest possible performance mode for the device.""" | 95 """Sets the highest possible performance mode for the device.""" |
| 28 self._SetScalingGovernorInternal('performance') | 96 |
| 97 if not self._manage_cpus_manually: | |
| 98 for cpu in xrange(self._kernel_max + 1): | |
| 99 self._SetScalingGovernorInternal(cpu, 'performance') | |
| 100 else: | |
| 101 # Stop the 'mpdecision' hotplug manager to get a constant number of CPUs | |
| 102 # online when running tests. TODO(pasko): stop 'thermald'. | |
|
bulach
2013/11/19 15:13:57
make sure you send a heads up to chrome-perf-sheri
pasko
2013/11/19 18:00:08
Yes, I am planning to let sheriffs know, this can
| |
| 103 self._adb.RunShellCommandWithSU('stop mpdecision') | |
| 104 for cpu in xrange(self._kernel_max + 1): | |
| 105 if cpu in self._cpus_to_manage: | |
| 106 self._BringCpuOnline(cpu) | |
| 107 self._SetScalingGovernorInternal(cpu, 'performance') | |
| 108 else: | |
| 109 self._BringCpuOffline(cpu) | |
| 29 | 110 |
| 30 def SetDefaultPerfMode(self): | 111 def SetDefaultPerfMode(self): |
| 31 """Sets the performance mode for the device to its default mode.""" | 112 """Sets the performance mode for the device to its default mode.""" |
| 113 | |
| 114 self._LogCurrentCpuFrequencyInfo() | |
| 32 product_model = self._adb.GetProductModel() | 115 product_model = self._adb.GetProductModel() |
| 33 governor_mode = { | 116 governor_mode = { |
| 34 'GT-I9300': 'pegasusq', | 117 'GT-I9300': 'pegasusq', |
| 35 'Galaxy Nexus': 'interactive', | 118 'Galaxy Nexus': 'interactive', |
| 36 'Nexus 4': 'ondemand', | 119 'Nexus 4': 'ondemand', |
| 120 'Nexus 5': 'ondemand', | |
| 37 'Nexus 7': 'interactive', | 121 'Nexus 7': 'interactive', |
| 38 'Nexus 10': 'interactive' | 122 'Nexus 10': 'interactive' |
| 39 }.get(product_model, 'ondemand') | 123 }.get(product_model, 'ondemand') |
| 40 self._SetScalingGovernorInternal(governor_mode) | 124 if not self._manage_cpus_manually: |
| 125 # Set the default perf mode only if no CPUs were forced online. | |
| 126 for cpu in xrange(self._kernel_max + 1): | |
| 127 self._SetScalingGovernorInternal(cpu, governor_mode) | |
| 128 # If 'mpdecision' is present on the system, it will manage CPU | |
| 129 # online/offline state, otherwise it is a no-op. | |
| 130 self._adb.RunShellCommandWithSU('start mpdecision') | |
| 41 | 131 |
| 42 def RestoreOriginalPerfMode(self): | 132 def RestoreOriginalPerfMode(self): |
| 43 """Resets the original performance mode of the device.""" | 133 """Resets the original performance mode of the device.""" |
| 44 self._SetScalingGovernorInternal(self._original_scaling_governor) | |
| 45 | 134 |
| 46 def _SetScalingGovernorInternal(self, value): | 135 self._LogCurrentCpuFrequencyInfo() |
| 47 for cpu in range(self._kernel_max + 1): | 136 if not self._manage_cpus_manually: |
| 48 scaling_governor_file = PerfControl._SCALING_GOVERNOR_FMT % cpu | 137 for cpu in xrange(self._kernel_max + 1): |
| 49 if self._adb.FileExistsOnDevice(scaling_governor_file): | 138 self._SetScalingGovernorInternal(cpu, self._original_scaling_governor) |
| 50 logging.info('Writing scaling governor mode \'%s\' -> %s', | 139 else: |
| 51 value, scaling_governor_file) | 140 for cpu in xrange(self._kernel_max + 1): |
| 52 self._adb.SetProtectedFileContents(scaling_governor_file, value) | 141 if cpu in self._cpus_on_originally: |
| 142 self._BringCpuOnline(cpu) | |
| 143 self._SetScalingGovernorInternal(cpu, self._original_scaling_governor) | |
| 144 else: | |
| 145 self._SetScalingGovernorInternal(cpu, self._original_scaling_governor) | |
| 146 self._BringCpuOffline(cpu) | |
| 147 self._adb.RunShellCommandWithSU('start mpdecision') | |
| 148 | |
| 149 def _SetScalingGovernorInternal(self, cpu, value): | |
| 150 scaling_governor_file = PerfControl._SCALING_GOVERNOR_FMT % cpu | |
| 151 if (self._manage_cpus_manually or | |
| 152 self._adb.FileExistsOnDevice(scaling_governor_file)): | |
| 153 logging.info('Writing scaling governor mode "%s" -> %s', | |
| 154 value, scaling_governor_file) | |
| 155 self._adb.SetProtectedFileContents(scaling_governor_file, value) | |
| OLD | NEW |