1# Copyright (c) 2010 The Chromium OS Authors. All rights reserved. 2# Use of this source code is governed by a BSD-style license that can be 3# found in the LICENSE file. 4 5import glob, logging, os 6from autotest_lib.client.bin import test 7from autotest_lib.client.common_lib import error, utils 8 9SYSFS_CPUQUIET_ENABLE = '/sys/devices/system/cpu/cpuquiet/tegra_cpuquiet/enable' 10SYSFS_INTEL_PSTATE_PATH = '/sys/devices/system/cpu/intel_pstate' 11 12class power_CPUFreq(test.test): 13 version = 1 14 15 def initialize(self): 16 # Store the setting if the system has CPUQuiet feature 17 if os.path.exists(SYSFS_CPUQUIET_ENABLE): 18 self.is_cpuquiet_enabled = utils.read_file(SYSFS_CPUQUIET_ENABLE) 19 utils.write_one_line(SYSFS_CPUQUIET_ENABLE, '0') 20 21 def run_once(self): 22 # TODO(crbug.com/485276) Revisit this exception once we've refactored 23 # test to account for intel_pstate cpufreq driver 24 if os.path.exists(SYSFS_INTEL_PSTATE_PATH): 25 raise error.TestNAError('Test does NOT support intel_pstate driver') 26 27 cpufreq_path = '/sys/devices/system/cpu/cpu*/cpufreq' 28 29 dirs = glob.glob(cpufreq_path) 30 if not dirs: 31 raise error.TestFail('cpufreq not supported') 32 33 keyvals = {} 34 try: 35 # First attempt to set all frequencies on each core before going 36 # on to the next core. 37 self.test_cores_in_series(dirs) 38 # Record that it was the first test that passed. 39 keyvals['test_cores_in_series'] = 1 40 except error.TestFail as exception: 41 if str(exception) == 'Unable to set frequency': 42 # If test_cores_in_series fails, try to set each frequency for 43 # all cores before moving on to the next frequency. 44 45 self.test_cores_in_parallel(dirs) 46 # Record that it was the second test that passed. 47 keyvals['test_cores_in_parallel'] = 1 48 else: 49 raise exception 50 51 self.write_perf_keyval(keyvals); 52 53 def test_cores_in_series(self, dirs): 54 for dir in dirs: 55 cpu = cpufreq(dir) 56 57 if 'userspace' not in cpu.get_available_governors(): 58 raise error.TestError('userspace governor not supported') 59 60 available_frequencies = cpu.get_available_frequencies() 61 if len(available_frequencies) == 1: 62 raise error.TestFail('Not enough frequencies supported!') 63 64 # save cpufreq state so that it can be restored at the end 65 # of the test 66 cpu.save_state() 67 68 # set cpufreq governor to userspace 69 cpu.set_governor('userspace') 70 71 # cycle through all available frequencies 72 for freq in available_frequencies: 73 cpu.set_frequency(freq) 74 if freq != cpu.get_current_frequency(): 75 cpu.restore_state() 76 raise error.TestFail('Unable to set frequency') 77 78 # restore cpufreq state 79 cpu.restore_state() 80 81 def test_cores_in_parallel(self, dirs): 82 cpus = [cpufreq(dir) for dir in dirs] 83 cpu0 = cpus[0] 84 85 # Use the first CPU's frequencies for all CPUs. Assume that they are 86 # the same. 87 available_frequencies = cpu0.get_available_frequencies() 88 if len(available_frequencies) == 1: 89 raise error.TestFail('Not enough frequencies supported!') 90 91 for cpu in cpus: 92 if 'userspace' not in cpu.get_available_governors(): 93 raise error.TestError('userspace governor not supported') 94 95 # save cpufreq state so that it can be restored at the end 96 # of the test 97 cpu.save_state() 98 99 # set cpufreq governor to userspace 100 cpu.set_governor('userspace') 101 102 # cycle through all available frequencies 103 for freq in available_frequencies: 104 for cpu in cpus: 105 cpu.set_frequency(freq) 106 for cpu in cpus: 107 if freq != cpu.get_current_frequency(): 108 cpu.restore_state() 109 raise error.TestFail('Unable to set frequency') 110 111 for cpu in cpus: 112 # restore cpufreq state 113 cpu.restore_state() 114 115 def cleanup(self): 116 # Restore the original setting if system has CPUQuiet feature 117 if os.path.exists(SYSFS_CPUQUIET_ENABLE): 118 utils.open_write_close( 119 SYSFS_CPUQUIET_ENABLE, self.is_cpuquiet_enabled) 120 121class cpufreq(object): 122 def __init__(self, path): 123 self.__base_path = path 124 self.__save_files_list = ['scaling_max_freq', 'scaling_min_freq', 125 'scaling_governor'] 126 127 128 def __write_file(self, file_name, data): 129 path = os.path.join(self.__base_path, file_name) 130 utils.open_write_close(path, data) 131 132 133 def __read_file(self, file_name): 134 path = os.path.join(self.__base_path, file_name) 135 f = open(path, 'r') 136 data = f.read() 137 f.close() 138 return data 139 140 141 def save_state(self): 142 logging.info('saving state:') 143 for file in self.__save_files_list: 144 data = self.__read_file(file) 145 setattr(self, file, data) 146 logging.info(file + ': ' + data) 147 148 149 def restore_state(self): 150 logging.info('restoring state:') 151 for file in self.__save_files_list: 152 # Sometimes a newline gets appended to a data string and it throws 153 # an error when being written to a sysfs file. Call strip() to 154 # eliminateextra whitespace characters so it can be written cleanly 155 # to the file. 156 data = getattr(self, file).strip() 157 logging.info(file + ': ' + data) 158 self.__write_file(file, data) 159 160 161 def get_available_governors(self): 162 governors = self.__read_file('scaling_available_governors') 163 logging.info('available governors: %s' % governors) 164 return governors.split() 165 166 167 def get_current_governor(self): 168 governor = self.__read_file('scaling_governor') 169 logging.info('current governor: %s' % governor) 170 return governor.split()[0] 171 172 173 def set_governor(self, governor): 174 logging.info('setting governor to %s' % governor) 175 self.__write_file('scaling_governor', governor) 176 177 178 def get_available_frequencies(self): 179 frequencies = self.__read_file('scaling_available_frequencies') 180 logging.info('available frequencies: %s' % frequencies) 181 return [int(i) for i in frequencies.split()] 182 183 184 def get_current_frequency(self): 185 freq = int(self.__read_file('scaling_cur_freq')) 186 logging.info('current frequency: %s' % freq) 187 return freq 188 189 190 def set_frequency(self, frequency): 191 logging.info('setting frequency to %d' % frequency) 192 if frequency >= self.get_current_frequency(): 193 file_list = ['scaling_max_freq', 'scaling_min_freq', 194 'scaling_setspeed'] 195 else: 196 file_list = ['scaling_min_freq', 'scaling_max_freq', 197 'scaling_setspeed'] 198 199 for file in file_list: 200 self.__write_file(file, str(frequency)) 201