254 lines
		
	
	
		
			9.0 KiB
		
	
	
	
		
			Python
		
	
	
	
			
		
		
	
	
			254 lines
		
	
	
		
			9.0 KiB
		
	
	
	
		
			Python
		
	
	
	
| # 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
 | |
| import logging
 | |
| import os
 | |
| import time
 | |
| 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):
 | |
|         cpufreq_path = '/sys/devices/system/cpu/cpu*/cpufreq'
 | |
| 
 | |
|         dirs = glob.glob(cpufreq_path)
 | |
|         if not dirs:
 | |
|             raise error.TestFail('cpufreq not supported')
 | |
| 
 | |
|         self._cpufreq_dirs = dirs
 | |
|         self._cpus = [cpufreq(dirname) for dirname in dirs]
 | |
|         for cpu in self._cpus:
 | |
|             cpu.save_state()
 | |
| 
 | |
|         # 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')
 | |
| 
 | |
|         keyvals = {}
 | |
|         try:
 | |
|             # First attempt to set all frequencies on each core before going
 | |
|             # on to the next core.
 | |
|             self.test_cores_in_series()
 | |
|             # 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.
 | |
|                 logging.debug('trying to set freq in parallel')
 | |
|                 self.test_cores_in_parallel()
 | |
|                 # 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):
 | |
|         for cpu in self._cpus:
 | |
|             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!')
 | |
| 
 | |
|             # set cpufreq governor to userspace
 | |
|             cpu.set_governor('userspace')
 | |
| 
 | |
|             # cycle through all available frequencies
 | |
|             for freq in available_frequencies:
 | |
|                 cpu.set_frequency(freq)
 | |
|                 if not self.compare_freqs(freq, cpu):
 | |
|                     raise error.TestFail('Unable to set frequency')
 | |
| 
 | |
|     def test_cores_in_parallel(self):
 | |
|         cpus = self._cpus
 | |
|         cpu0 = self._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')
 | |
| 
 | |
|             # 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 not self.compare_freqs(freq, cpu):
 | |
|                     raise error.TestFail('Unable to set frequency')
 | |
| 
 | |
|     def compare_freqs(self, set_freq, cpu):
 | |
|         # crbug.com/848309 : older kernels have race between setting
 | |
|         # governor and access to setting frequency so add a retry
 | |
|         try:
 | |
|             freq = cpu.get_current_frequency()
 | |
|         except IOError:
 | |
|             logging.warn('Frequency getting failed.  Retrying once.')
 | |
|             time.sleep(.1)
 | |
|             freq = cpu.get_current_frequency()
 | |
| 
 | |
|         logging.debug('frequency set:%d vs actual:%d',
 | |
|                       set_freq, freq)
 | |
| 
 | |
|         # setting freq to a particular frequency isn't reliable so just test
 | |
|         # that driver allows setting & getting.
 | |
|         if cpu.get_driver() == 'acpi-cpufreq':
 | |
|             return True
 | |
| 
 | |
|         return set_freq == freq
 | |
| 
 | |
|     def cleanup(self):
 | |
|         if self._cpus:
 | |
|             for cpu in self._cpus:
 | |
|                 # restore cpufreq state
 | |
|                 cpu.restore_state()
 | |
| 
 | |
|         # 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'
 | |
|         ]
 | |
|         self._freqs = None
 | |
|         # disable boost to limit how much freq can vary in userspace mode
 | |
|         if self.get_driver() == 'acpi-cpufreq':
 | |
|             self.disable_boost()
 | |
| 
 | |
|     def __del__(self):
 | |
|         if self.get_driver() == 'acpi-cpufreq':
 | |
|             self.enable_boost()
 | |
| 
 | |
|     def __write_file(self, file_name, data):
 | |
|         path = os.path.join(self.__base_path, file_name)
 | |
|         try:
 | |
|             utils.open_write_close(path, data)
 | |
|         except IOError as e:
 | |
|             logging.warn('write of %s failed: %s', path, str(e))
 | |
| 
 | |
|     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 fname in self.__save_files_list:
 | |
|             data = self.__read_file(fname)
 | |
|             setattr(self, fname, data)
 | |
|             logging.info(fname + ': ' + data)
 | |
| 
 | |
|     def restore_state(self):
 | |
|         logging.info('restoring state:')
 | |
|         for fname 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, fname).strip()
 | |
|             logging.info(fname + ': ' + data)
 | |
|             self.__write_file(fname, 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 get_driver(self):
 | |
|         driver = self.__read_file('scaling_driver')
 | |
|         logging.info('current driver: %s', driver)
 | |
|         return driver.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):
 | |
|         if self._freqs:
 | |
|             return self._freqs
 | |
|         frequencies = self.__read_file('scaling_available_frequencies')
 | |
|         logging.info('available frequencies: %s', frequencies)
 | |
|         self._freqs = [int(i) for i in frequencies.split()]
 | |
|         return self._freqs
 | |
| 
 | |
|     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 fname in file_list:
 | |
|             self.__write_file(fname, str(frequency))
 | |
| 
 | |
|     def disable_boost(self):
 | |
|         """Disable boost.
 | |
| 
 | |
|         Note, boost is NOT a per-cpu parameter,
 | |
|           /sys/device/system/cpu/cpufreq/boost
 | |
| 
 | |
|         So code below would unnecessarily disable it per-cpu but that should not
 | |
|         cause any issues.
 | |
|         """
 | |
|         logging.debug('Disable boost')
 | |
|         self.__write_file('../../cpufreq/boost', '0')
 | |
| 
 | |
|     def enable_boost(self):
 | |
|         """Enable boost.
 | |
| 
 | |
|         Note, boost is NOT a per-cpu parameter,
 | |
|           /sys/device/system/cpu/cpufreq/boost
 | |
| 
 | |
|         So code below would unnecessarily enable it per-cpu but that should not
 | |
|         cause any issues.
 | |
|         """
 | |
|         logging.debug('Enable boost')
 | |
|         self.__write_file('../../cpufreq/boost', '1')
 |