# Copyright (c) 2010 The Chromium OS Authors. All rights reserved. # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. import glob, logging, os from autotest_lib.client.bin import test from autotest_lib.client.common_lib import error, utils SYSFS_CPUQUIET_ENABLE = '/sys/devices/system/cpu/cpuquiet/tegra_cpuquiet/enable' SYSFS_INTEL_PSTATE_PATH = '/sys/devices/system/cpu/intel_pstate' class power_CPUFreq(test.test): version = 1 def initialize(self): # Store the setting if the system has CPUQuiet feature if os.path.exists(SYSFS_CPUQUIET_ENABLE): self.is_cpuquiet_enabled = utils.read_file(SYSFS_CPUQUIET_ENABLE) utils.write_one_line(SYSFS_CPUQUIET_ENABLE, '0') def run_once(self): # TODO(crbug.com/485276) Revisit this exception once we've refactored # test to account for intel_pstate cpufreq driver if os.path.exists(SYSFS_INTEL_PSTATE_PATH): raise error.TestNAError('Test does NOT support intel_pstate driver') cpufreq_path = '/sys/devices/system/cpu/cpu*/cpufreq' dirs = glob.glob(cpufreq_path) if not dirs: raise error.TestFail('cpufreq not supported') keyvals = {} try: # First attempt to set all frequencies on each core before going # on to the next core. self.test_cores_in_series(dirs) # Record that it was the first test that passed. keyvals['test_cores_in_series'] = 1 except error.TestFail as exception: if str(exception) == 'Unable to set frequency': # If test_cores_in_series fails, try to set each frequency for # all cores before moving on to the next frequency. self.test_cores_in_parallel(dirs) # Record that it was the second test that passed. keyvals['test_cores_in_parallel'] = 1 else: raise exception self.write_perf_keyval(keyvals); def test_cores_in_series(self, dirs): for dir in dirs: cpu = cpufreq(dir) if 'userspace' not in cpu.get_available_governors(): raise error.TestError('userspace governor not supported') available_frequencies = cpu.get_available_frequencies() if len(available_frequencies) == 1: raise error.TestFail('Not enough frequencies supported!') # save cpufreq state so that it can be restored at the end # of the test cpu.save_state() # set cpufreq governor to userspace cpu.set_governor('userspace') # cycle through all available frequencies for freq in available_frequencies: cpu.set_frequency(freq) if freq != cpu.get_current_frequency(): cpu.restore_state() raise error.TestFail('Unable to set frequency') # restore cpufreq state cpu.restore_state() def test_cores_in_parallel(self, dirs): cpus = [cpufreq(dir) for dir in dirs] cpu0 = cpus[0] # Use the first CPU's frequencies for all CPUs. Assume that they are # the same. available_frequencies = cpu0.get_available_frequencies() if len(available_frequencies) == 1: raise error.TestFail('Not enough frequencies supported!') for cpu in cpus: if 'userspace' not in cpu.get_available_governors(): raise error.TestError('userspace governor not supported') # save cpufreq state so that it can be restored at the end # of the test cpu.save_state() # set cpufreq governor to userspace cpu.set_governor('userspace') # cycle through all available frequencies for freq in available_frequencies: for cpu in cpus: cpu.set_frequency(freq) for cpu in cpus: if freq != cpu.get_current_frequency(): cpu.restore_state() raise error.TestFail('Unable to set frequency') for cpu in cpus: # restore cpufreq state cpu.restore_state() def cleanup(self): # Restore the original setting if system has CPUQuiet feature if os.path.exists(SYSFS_CPUQUIET_ENABLE): utils.open_write_close( SYSFS_CPUQUIET_ENABLE, self.is_cpuquiet_enabled) class cpufreq(object): def __init__(self, path): self.__base_path = path self.__save_files_list = ['scaling_max_freq', 'scaling_min_freq', 'scaling_governor'] def __write_file(self, file_name, data): path = os.path.join(self.__base_path, file_name) utils.open_write_close(path, data) def __read_file(self, file_name): path = os.path.join(self.__base_path, file_name) f = open(path, 'r') data = f.read() f.close() return data def save_state(self): logging.info('saving state:') for file in self.__save_files_list: data = self.__read_file(file) setattr(self, file, data) logging.info(file + ': ' + data) def restore_state(self): logging.info('restoring state:') for file in self.__save_files_list: # Sometimes a newline gets appended to a data string and it throws # an error when being written to a sysfs file. Call strip() to # eliminateextra whitespace characters so it can be written cleanly # to the file. data = getattr(self, file).strip() logging.info(file + ': ' + data) self.__write_file(file, data) def get_available_governors(self): governors = self.__read_file('scaling_available_governors') logging.info('available governors: %s' % governors) return governors.split() def get_current_governor(self): governor = self.__read_file('scaling_governor') logging.info('current governor: %s' % governor) return governor.split()[0] def set_governor(self, governor): logging.info('setting governor to %s' % governor) self.__write_file('scaling_governor', governor) def get_available_frequencies(self): frequencies = self.__read_file('scaling_available_frequencies') logging.info('available frequencies: %s' % frequencies) return [int(i) for i in frequencies.split()] def get_current_frequency(self): freq = int(self.__read_file('scaling_cur_freq')) logging.info('current frequency: %s' % freq) return freq def set_frequency(self, frequency): logging.info('setting frequency to %d' % frequency) if frequency >= self.get_current_frequency(): file_list = ['scaling_max_freq', 'scaling_min_freq', 'scaling_setspeed'] else: file_list = ['scaling_min_freq', 'scaling_max_freq', 'scaling_setspeed'] for file in file_list: self.__write_file(file, str(frequency))