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 ] | |
bulach
2013/11/15 17:54:43
nit: align with _ from 17
pasko
2013/11/18 15:11:18
Done.
| |
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 # 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
| |
36 # Other device types are either hard to manage properly or we did not decide | |
37 # what settings look 'typical' for them. 'Galaxy Nexus' and 'Nexus 10' seem | |
38 # to use both cores all time without hotplugging them manually, but we still | |
39 # may need to manage their frequency later. TODO(pasko): manage Nexus 7 | |
40 # manually, v1 and v2 differ significantly. | |
41 # | |
42 # *Not managing* CPUs manually means that only a subset of CPU properties | |
43 # are updated (scaling governor only now) and only for those CPUs | |
44 # represented by sysfs at the moment (/sys/devices/system/cpu/cpuX/...) | |
45 self._manage_cpus_manually = False | |
46 cpu_indexes_to_manage_manually = { | |
47 'Nexus 4': [0, 1], | |
48 '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
| |
49 } | |
50 device_model = self._adb.GetProductModel() | |
51 if device_model in cpu_indexes_to_manage_manually: | |
52 self._manage_cpus_manually = True | |
53 self._cpus_to_manage = cpu_indexes_to_manage_manually[device_model] | |
54 self._cpus_on_originally = [] | |
55 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.
| |
56 if '1' in self._ReadProtectedFile(PerfControl._CPU_ONLINE_FMT % cpu): | |
57 self._cpus_on_originally.append(cpu) | |
58 | |
59 def _BringCpuOffline(self, cpu_index): | |
60 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.
| |
61 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
| |
62 | |
63 def _BringCpuOnline(self, cpu_index): | |
64 "Brings a CPU core online, waits for it to show up in sysfs." | |
65 | |
66 logging.info('Bringing CPU #%d online.' %cpu_index) | |
67 times_to_wait_left = 5 | |
68 cpu_online_file = PerfControl._CPU_ONLINE_FMT % cpu_index | |
69 while (True): | |
70 self._adb.SetProtectedFileContents(cpu_online_file, '1') | |
71 if '1' in self._ReadProtectedFile(cpu_online_file): | |
72 break | |
73 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.
| |
74 if times_to_wait_left == 0: | |
75 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
| |
76 break | |
77 times_to_wait_left -= 1 | |
78 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.
| |
79 cpu_index) | |
80 time.sleep(0.1) | |
81 | |
82 def _ReadProtectedFile(self, file_name): | |
83 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.
| |
84 | |
85 def _LogCurrentCpuFrequencyInfo(self): | |
86 for cpu in xrange(self._kernel_max + 1): | |
87 for stat_name in PerfControl._SCALING_FREQUENCY_STAT_NAMES: | |
88 stat_file_name = (PerfControl._CPU_DIR_FMT + stat_name) % cpu; | |
89 if self._adb.FileExistsOnDevice(stat_file_name): | |
90 info = self._ReadProtectedFile(stat_file_name) | |
91 logging.info('CPU #%d frequency info: %s: %s', cpu, stat_name, info) | |
25 | 92 |
26 def SetHighPerfMode(self): | 93 def SetHighPerfMode(self): |
27 """Sets the highest possible performance mode for the device.""" | 94 """Sets the highest possible performance mode for the device.""" |
28 self._SetScalingGovernorInternal('performance') | 95 |
96 if not self._manage_cpus_manually: | |
97 for cpu in xrange(self._kernel_max + 1): | |
98 self._SetScalingGovernorInternal(cpu, 'performance') | |
99 else: | |
100 # 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
| |
101 # 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
| |
102 self._adb.RunShellCommandWithSU('stop mpdecision') | |
103 for cpu in xrange(self._kernel_max + 1): | |
104 if cpu in self._cpus_to_manage: | |
105 self._BringCpuOnline(cpu) | |
106 self._SetScalingGovernorInternal(cpu, 'performance') | |
107 else: | |
108 self._BringCpuOffline(cpu) | |
29 | 109 |
30 def SetDefaultPerfMode(self): | 110 def SetDefaultPerfMode(self): |
31 """Sets the performance mode for the device to its default mode.""" | 111 """Sets the performance mode for the device to its default mode.""" |
112 | |
113 self._LogCurrentCpuFrequencyInfo() | |
32 product_model = self._adb.GetProductModel() | 114 product_model = self._adb.GetProductModel() |
33 governor_mode = { | 115 governor_mode = { |
34 'GT-I9300': 'pegasusq', | 116 'GT-I9300': 'pegasusq', |
35 'Galaxy Nexus': 'interactive', | 117 'Galaxy Nexus': 'interactive', |
36 'Nexus 4': 'ondemand', | 118 'Nexus 4': 'ondemand', |
aberent
2013/11/15 19:00:12
Please add 'Nexus 5' to this list.
pasko
2013/11/18 15:11:18
Done.
| |
37 'Nexus 7': 'interactive', | 119 'Nexus 7': 'interactive', |
38 'Nexus 10': 'interactive' | 120 'Nexus 10': 'interactive' |
39 }.get(product_model, 'ondemand') | 121 }.get(product_model, 'ondemand') |
40 self._SetScalingGovernorInternal(governor_mode) | 122 if not self._manage_cpus_manually: |
123 for cpu in xrange(self._kernel_max + 1): | |
124 self._SetScalingGovernorInternal(cpu, governor_mode) | |
125 else: | |
126 # What is the 'Default' state for CPU online/offline state if we manage it | |
127 # manually? It is the choice of CPU presence that was made earlier. | |
128 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.
| |
129 # If 'mpdecision' is present on the system, it will manage CPU | |
130 # online/offline state, otherwise it is a no-op. | |
131 self._adb.RunShellCommandWithSU('start mpdecision') | |
41 | 132 |
42 def RestoreOriginalPerfMode(self): | 133 def RestoreOriginalPerfMode(self): |
43 """Resets the original performance mode of the device.""" | 134 """Resets the original performance mode of the device.""" |
44 self._SetScalingGovernorInternal(self._original_scaling_governor) | |
45 | 135 |
46 def _SetScalingGovernorInternal(self, value): | 136 self._LogCurrentCpuFrequencyInfo() |
47 for cpu in range(self._kernel_max + 1): | 137 if not self._manage_cpus_manually: |
48 scaling_governor_file = PerfControl._SCALING_GOVERNOR_FMT % cpu | 138 for cpu in xrange(self._kernel_max + 1): |
49 if self._adb.FileExistsOnDevice(scaling_governor_file): | 139 self._SetScalingGovernorInternal(cpu, self._original_scaling_governor) |
50 logging.info('Writing scaling governor mode \'%s\' -> %s', | 140 else: |
51 value, scaling_governor_file) | 141 for cpu in xrange(self._kernel_max + 1): |
52 self._adb.SetProtectedFileContents(scaling_governor_file, value) | 142 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
| |
143 self._BringCpuOnline(cpu) | |
144 else: | |
145 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.
| |
146 self._adb.RunShellCommandWithSU('start mpdecision') | |
147 | |
148 def _SetScalingGovernorInternal(self, cpu, value): | |
149 scaling_governor_file = PerfControl._SCALING_GOVERNOR_FMT % cpu | |
150 if (self._manage_cpus_manually or | |
151 self._adb.FileExistsOnDevice(scaling_governor_file)): | |
152 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.
| |
153 value, scaling_governor_file) | |
154 self._adb.SetProtectedFileContents(scaling_governor_file, value) | |
OLD | NEW |