Chromium Code Reviews| Index: build/android/pylib/perf/perf_control.py |
| diff --git a/build/android/pylib/perf/perf_control.py b/build/android/pylib/perf/perf_control.py |
| index e289991f84abd918780ce520db4467e3ceb5ec64..0f617380276a8cbf8aa237e1ca1d5e10e6549e7f 100644 |
| --- a/build/android/pylib/perf/perf_control.py |
| +++ b/build/android/pylib/perf/perf_control.py |
| @@ -4,13 +4,21 @@ |
| import logging |
| +import time |
| 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') |
| + |
| _KERNEL_MAX = '/sys/devices/system/cpu/kernel_max' |
| + _CPU_DIR_FMT = '/sys/devices/system/cpu/cpu%d/' |
| + _SCALING_GOVERNOR_FMT = _CPU_DIR_FMT + 'cpufreq/scaling_governor' |
| + _CPU_ONLINE_FMT = _CPU_DIR_FMT + 'online' |
| + _SCALING_FREQUENCY_STAT_NAMES = [ |
| + 'cpufreq/scaling_min_freq', |
| + 'cpufreq/scaling_max_freq', |
| + 'cpufreq/scaling_cur_freq', |
| + ] |
|
bulach
2013/11/15 17:54:43
nit: align with _ from 17
pasko
2013/11/18 15:11:18
Done.
|
| def __init__(self, adb): |
| self._adb = adb |
| @@ -22,13 +30,87 @@ class PerfControl(object): |
| self._original_scaling_governor = self._adb.GetFileContents( |
| PerfControl._SCALING_GOVERNOR_FMT % 0, |
| log_result=False)[0] |
| + self._LogCurrentCpuFrequencyInfo() |
| + |
| + # Manage CPUs on some device types manually to reduce variance in results. |
|
bulach
2013/11/15 17:54:43
"manually" is a bit misleading, and they're all "m
pasko
2013/11/18 15:11:18
I tried that, and it looks less readable to me to
bulach
2013/11/19 15:13:57
how about this:
extract cpu_indexes_to_manage_man
pasko
2013/11/19 18:00:08
I like "fully managed CPUs" as a term. Thanks!!
s
|
| + # Other device types are either hard to manage properly or we did not decide |
| + # what settings look 'typical' for them. 'Galaxy Nexus' and 'Nexus 10' seem |
| + # to use both cores all time without hotplugging them manually, but we still |
| + # may need to manage their frequency later. TODO(pasko): manage Nexus 7 |
| + # manually, v1 and v2 differ significantly. |
| + # |
| + # *Not managing* CPUs manually means that only a subset of CPU properties |
| + # are updated (scaling governor only now) and only for those CPUs |
| + # represented by sysfs at the moment (/sys/devices/system/cpu/cpuX/...) |
| + self._manage_cpus_manually = False |
| + cpu_indexes_to_manage_manually = { |
| + 'Nexus 4': [0, 1], |
| + 'Nexus 5': [0, 1], |
|
aberent
2013/11/15 19:00:12
What is your intention in only managing two of the
pasko
2013/11/18 15:11:18
I looked at a few pagecycler runs on the bot and f
|
| + } |
| + device_model = self._adb.GetProductModel() |
| + if device_model in cpu_indexes_to_manage_manually: |
| + self._manage_cpus_manually = True |
| + self._cpus_to_manage = cpu_indexes_to_manage_manually[device_model] |
| + self._cpus_on_originally = [] |
| + for cpu in xrange(self._kernel_max +1): |
|
bulach
2013/11/15 17:54:43
nit: space after +
pasko
2013/11/18 15:11:18
Done.
|
| + if '1' in self._ReadProtectedFile(PerfControl._CPU_ONLINE_FMT % cpu): |
| + self._cpus_on_originally.append(cpu) |
| + |
| + def _BringCpuOffline(self, cpu_index): |
| + logging.info('Bringing CPU #%d offline.' %cpu_index) |
|
bulach
2013/11/15 17:54:43
nit: logging takes format and vararg, so replace %
pasko
2013/11/18 15:11:18
Done.
|
| + self._adb.SetProtectedFileContents(PerfControl._CPU_ONLINE_FMT, '0') |
|
aberent
2013/11/15 19:00:12
This doesn't use cpu_index, how does it know which
pasko
2013/11/18 15:11:18
That's a great catch! Thank you! Do you think it m
|
| + |
| + def _BringCpuOnline(self, cpu_index): |
| + "Brings a CPU core online, waits for it to show up in sysfs." |
| + |
| + logging.info('Bringing CPU #%d online.' %cpu_index) |
| + times_to_wait_left = 5 |
| + cpu_online_file = PerfControl._CPU_ONLINE_FMT % cpu_index |
| + while (True): |
| + self._adb.SetProtectedFileContents(cpu_online_file, '1') |
| + if '1' in self._ReadProtectedFile(cpu_online_file): |
| + break |
| + else: |
|
bulach
2013/11/15 17:54:43
nit: no need for else, unindent the following bloc
pasko
2013/11/18 15:11:18
Done.
|
| + if times_to_wait_left == 0: |
| + logging.warning('Gave up bringing CPU %d online') |
|
bulach
2013/11/15 17:54:43
nit: missing ", cpu_index"
pasko
2013/11/18 15:11:18
Thank you! You know, I really got used to GCC warn
|
| + break |
| + times_to_wait_left -= 1 |
| + logging.warning('Could not bring CPU %d online, retrying..' % |
|
bulach
2013/11/15 17:54:43
nit: s/%/,/
pasko
2013/11/18 15:11:18
Done.
|
| + cpu_index) |
| + time.sleep(0.1) |
| + |
| + def _ReadProtectedFile(self, file_name): |
| + return '\n'.join(self._adb.GetProtectedFileContents(file_name)) |
|
bulach
2013/11/15 17:54:43
it this function needed? :)
line 71 would be fine:
pasko
2013/11/18 15:11:18
This function made 3 lines (line 56, 72 and 90) sh
bulach
2013/11/19 15:13:57
perhaps then name it as _GetProtectedFileContents
pasko
2013/11/19 18:00:08
Whichever you like. Done.
|
| + |
| + def _LogCurrentCpuFrequencyInfo(self): |
| + for cpu in xrange(self._kernel_max + 1): |
| + for stat_name in PerfControl._SCALING_FREQUENCY_STAT_NAMES: |
| + stat_file_name = (PerfControl._CPU_DIR_FMT + stat_name) % cpu; |
| + if self._adb.FileExistsOnDevice(stat_file_name): |
| + info = self._ReadProtectedFile(stat_file_name) |
| + logging.info('CPU #%d frequency info: %s: %s', cpu, stat_name, info) |
| def SetHighPerfMode(self): |
| """Sets the highest possible performance mode for the device.""" |
| - self._SetScalingGovernorInternal('performance') |
| + |
| + if not self._manage_cpus_manually: |
| + for cpu in xrange(self._kernel_max + 1): |
| + self._SetScalingGovernorInternal(cpu, 'performance') |
| + else: |
| + # Stop the proprietary 'mpdecision' hotplug manager to get a constant |
|
bulach
2013/11/15 17:54:43
is "proprietary" relevant? How about just "Stop 'm
pasko
2013/11/18 15:11:18
no, not relevant, I was just angry :) Removed. I w
|
| + # number of CPUs online when running tests. TODO(pasko): stop 'thermald'. |
|
aberent
2013/11/15 19:00:12
Isn't stopping thermald going to burn out the devi
pasko
2013/11/18 15:11:18
Yes, it certainly may. So I was thinking of having
aberent
2013/11/18 16:32:05
Makes sense, if we can find devices that will run
|
| + self._adb.RunShellCommandWithSU('stop mpdecision') |
| + for cpu in xrange(self._kernel_max + 1): |
| + if cpu in self._cpus_to_manage: |
| + self._BringCpuOnline(cpu) |
| + self._SetScalingGovernorInternal(cpu, 'performance') |
| + else: |
| + self._BringCpuOffline(cpu) |
| def SetDefaultPerfMode(self): |
| """Sets the performance mode for the device to its default mode.""" |
| + |
| + self._LogCurrentCpuFrequencyInfo() |
| product_model = self._adb.GetProductModel() |
| governor_mode = { |
| 'GT-I9300': 'pegasusq', |
| @@ -37,16 +119,36 @@ class PerfControl(object): |
| 'Nexus 7': 'interactive', |
| 'Nexus 10': 'interactive' |
| }.get(product_model, 'ondemand') |
| - self._SetScalingGovernorInternal(governor_mode) |
| + if not self._manage_cpus_manually: |
| + for cpu in xrange(self._kernel_max + 1): |
| + self._SetScalingGovernorInternal(cpu, governor_mode) |
| + else: |
| + # What is the 'Default' state for CPU online/offline state if we manage it |
| + # manually? It is the choice of CPU presence that was made earlier. |
| + pass |
|
bulach
2013/11/15 17:54:43
sorry, this block is a bit confusing :)
how about
pasko
2013/11/18 15:11:18
Sorry, it was. Good suggestion. Done.
|
| + # If 'mpdecision' is present on the system, it will manage CPU |
| + # online/offline state, otherwise it is a no-op. |
| + self._adb.RunShellCommandWithSU('start mpdecision') |
| def RestoreOriginalPerfMode(self): |
| """Resets the original performance mode of the device.""" |
| - self._SetScalingGovernorInternal(self._original_scaling_governor) |
| - |
| - def _SetScalingGovernorInternal(self, value): |
| - for cpu in range(self._kernel_max + 1): |
| - scaling_governor_file = PerfControl._SCALING_GOVERNOR_FMT % cpu |
| - if self._adb.FileExistsOnDevice(scaling_governor_file): |
| - logging.info('Writing scaling governor mode \'%s\' -> %s', |
| - value, scaling_governor_file) |
| - self._adb.SetProtectedFileContents(scaling_governor_file, value) |
| + |
| + self._LogCurrentCpuFrequencyInfo() |
| + if not self._manage_cpus_manually: |
| + for cpu in xrange(self._kernel_max + 1): |
| + self._SetScalingGovernorInternal(cpu, self._original_scaling_governor) |
| + else: |
| + for cpu in xrange(self._kernel_max + 1): |
| + if cpu in self._cpus_on_originally: |
|
aberent
2013/11/15 19:00:12
I think if the CPU was both online originally and
pasko
2013/11/18 15:11:18
That's right. I forgot to restore the performance
|
| + self._BringCpuOnline(cpu) |
| + else: |
| + self._BringCpuOffline(cpu) |
|
aberent
2013/11/15 19:00:12
Does this clear the performance mode back to the d
pasko
2013/11/18 15:11:18
Done.
|
| + self._adb.RunShellCommandWithSU('start mpdecision') |
| + |
| + def _SetScalingGovernorInternal(self, cpu, value): |
| + scaling_governor_file = PerfControl._SCALING_GOVERNOR_FMT % cpu |
| + if (self._manage_cpus_manually or |
| + self._adb.FileExistsOnDevice(scaling_governor_file)): |
| + logging.info('Writing scaling governor mode \'%s\' -> %s', |
|
bulach
2013/11/15 17:54:43
nit: replace \' with "
pasko
2013/11/18 15:11:18
Done.
|
| + value, scaling_governor_file) |
| + self._adb.SetProtectedFileContents(scaling_governor_file, value) |