Home | History | Annotate | Download | only in power_CPUFreq
      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 
      5 import glob
      6 import logging
      7 import os
      8 import time
      9 from autotest_lib.client.bin import test
     10 from autotest_lib.client.common_lib import error, utils
     11 
     12 SYSFS_CPUQUIET_ENABLE = '/sys/devices/system/cpu/cpuquiet/tegra_cpuquiet/enable'
     13 SYSFS_INTEL_PSTATE_PATH = '/sys/devices/system/cpu/intel_pstate'
     14 
     15 
     16 class power_CPUFreq(test.test):
     17     version = 1
     18 
     19     def initialize(self):
     20         cpufreq_path = '/sys/devices/system/cpu/cpu*/cpufreq'
     21 
     22         dirs = glob.glob(cpufreq_path)
     23         if not dirs:
     24             raise error.TestFail('cpufreq not supported')
     25 
     26         self._cpufreq_dirs = dirs
     27         self._cpus = [cpufreq(dirname) for dirname in dirs]
     28         for cpu in self._cpus:
     29             cpu.save_state()
     30 
     31         # Store the setting if the system has CPUQuiet feature
     32         if os.path.exists(SYSFS_CPUQUIET_ENABLE):
     33             self.is_cpuquiet_enabled = utils.read_file(SYSFS_CPUQUIET_ENABLE)
     34             utils.write_one_line(SYSFS_CPUQUIET_ENABLE, '0')
     35 
     36     def run_once(self):
     37         # TODO(crbug.com/485276) Revisit this exception once we've refactored
     38         # test to account for intel_pstate cpufreq driver
     39         if os.path.exists(SYSFS_INTEL_PSTATE_PATH):
     40             raise error.TestNAError('Test does NOT support intel_pstate driver')
     41 
     42         keyvals = {}
     43         try:
     44             # First attempt to set all frequencies on each core before going
     45             # on to the next core.
     46             self.test_cores_in_series()
     47             # Record that it was the first test that passed.
     48             keyvals['test_cores_in_series'] = 1
     49         except error.TestFail as exception:
     50             if str(exception) == 'Unable to set frequency':
     51                 # If test_cores_in_series fails, try to set each frequency for
     52                 # all cores before moving on to the next frequency.
     53                 logging.debug('trying to set freq in parallel')
     54                 self.test_cores_in_parallel()
     55                 # Record that it was the second test that passed.
     56                 keyvals['test_cores_in_parallel'] = 1
     57             else:
     58                 raise exception
     59 
     60         self.write_perf_keyval(keyvals)
     61 
     62     def test_cores_in_series(self):
     63         for cpu in self._cpus:
     64             if 'userspace' not in cpu.get_available_governors():
     65                 raise error.TestError('userspace governor not supported')
     66 
     67             available_frequencies = cpu.get_available_frequencies()
     68             if len(available_frequencies) == 1:
     69                 raise error.TestFail('Not enough frequencies supported!')
     70 
     71             # set cpufreq governor to userspace
     72             cpu.set_governor('userspace')
     73 
     74             # cycle through all available frequencies
     75             for freq in available_frequencies:
     76                 cpu.set_frequency(freq)
     77                 if not self.compare_freqs(freq, cpu):
     78                     raise error.TestFail('Unable to set frequency')
     79 
     80     def test_cores_in_parallel(self):
     81         cpus = self._cpus
     82         cpu0 = self._cpus[0]
     83 
     84         # Use the first CPU's frequencies for all CPUs.  Assume that they are
     85         # the same.
     86         available_frequencies = cpu0.get_available_frequencies()
     87         if len(available_frequencies) == 1:
     88             raise error.TestFail('Not enough frequencies supported!')
     89 
     90         for cpu in cpus:
     91             if 'userspace' not in cpu.get_available_governors():
     92                 raise error.TestError('userspace governor not supported')
     93 
     94             # set cpufreq governor to userspace
     95             cpu.set_governor('userspace')
     96 
     97         # cycle through all available frequencies
     98         for freq in available_frequencies:
     99             for cpu in cpus:
    100                 cpu.set_frequency(freq)
    101             for cpu in cpus:
    102                 if not self.compare_freqs(freq, cpu):
    103                     raise error.TestFail('Unable to set frequency')
    104 
    105     def compare_freqs(self, set_freq, cpu):
    106         # crbug.com/848309 : older kernels have race between setting
    107         # governor and access to setting frequency so add a retry
    108         try:
    109             freq = cpu.get_current_frequency()
    110         except IOError:
    111             logging.warn('Frequency getting failed.  Retrying once.')
    112             time.sleep(.1)
    113             freq = cpu.get_current_frequency()
    114 
    115         logging.debug('frequency set:%d vs actual:%d',
    116                       set_freq, freq)
    117 
    118         # setting freq to a particular frequency isn't reliable so just test
    119         # that driver allows setting & getting.
    120         if cpu.get_driver() == 'acpi-cpufreq':
    121             return True
    122 
    123         return set_freq == freq
    124 
    125     def cleanup(self):
    126         if self._cpus:
    127             for cpu in self._cpus:
    128                 # restore cpufreq state
    129                 cpu.restore_state()
    130 
    131         # Restore the original setting if system has CPUQuiet feature
    132         if os.path.exists(SYSFS_CPUQUIET_ENABLE):
    133             utils.open_write_close(SYSFS_CPUQUIET_ENABLE,
    134                                    self.is_cpuquiet_enabled)
    135 
    136 
    137 class cpufreq(object):
    138 
    139     def __init__(self, path):
    140         self.__base_path = path
    141         self.__save_files_list = [
    142             'scaling_max_freq', 'scaling_min_freq', 'scaling_governor'
    143         ]
    144         self._freqs = None
    145         # disable boost to limit how much freq can vary in userspace mode
    146         if self.get_driver() == 'acpi-cpufreq':
    147             self.disable_boost()
    148 
    149     def __del__(self):
    150         if self.get_driver() == 'acpi-cpufreq':
    151             self.enable_boost()
    152 
    153     def __write_file(self, file_name, data):
    154         path = os.path.join(self.__base_path, file_name)
    155         try:
    156             utils.open_write_close(path, data)
    157         except IOError as e:
    158             logging.warn('write of %s failed: %s', path, str(e))
    159 
    160     def __read_file(self, file_name):
    161         path = os.path.join(self.__base_path, file_name)
    162         f = open(path, 'r')
    163         data = f.read()
    164         f.close()
    165         return data
    166 
    167     def save_state(self):
    168         logging.info('saving state:')
    169         for fname in self.__save_files_list:
    170             data = self.__read_file(fname)
    171             setattr(self, fname, data)
    172             logging.info(fname + ': ' + data)
    173 
    174     def restore_state(self):
    175         logging.info('restoring state:')
    176         for fname in self.__save_files_list:
    177             # Sometimes a newline gets appended to a data string and it throws
    178             # an error when being written to a sysfs file.  Call strip() to
    179             # eliminateextra whitespace characters so it can be written cleanly
    180             # to the file.
    181             data = getattr(self, fname).strip()
    182             logging.info(fname + ': ' + data)
    183             self.__write_file(fname, data)
    184 
    185     def get_available_governors(self):
    186         governors = self.__read_file('scaling_available_governors')
    187         logging.info('available governors: %s', governors)
    188         return governors.split()
    189 
    190     def get_current_governor(self):
    191         governor = self.__read_file('scaling_governor')
    192         logging.info('current governor: %s', governor)
    193         return governor.split()[0]
    194 
    195     def get_driver(self):
    196         driver = self.__read_file('scaling_driver')
    197         logging.info('current driver: %s', driver)
    198         return driver.split()[0]
    199 
    200     def set_governor(self, governor):
    201         logging.info('setting governor to %s', governor)
    202         self.__write_file('scaling_governor', governor)
    203 
    204     def get_available_frequencies(self):
    205         if self._freqs:
    206             return self._freqs
    207         frequencies = self.__read_file('scaling_available_frequencies')
    208         logging.info('available frequencies: %s', frequencies)
    209         self._freqs = [int(i) for i in frequencies.split()]
    210         return self._freqs
    211 
    212     def get_current_frequency(self):
    213         freq = int(self.__read_file('scaling_cur_freq'))
    214         logging.info('current frequency: %s', freq)
    215         return freq
    216 
    217     def set_frequency(self, frequency):
    218         logging.info('setting frequency to %d', frequency)
    219         if frequency >= self.get_current_frequency():
    220             file_list = [
    221                 'scaling_max_freq', 'scaling_min_freq', 'scaling_setspeed'
    222             ]
    223         else:
    224             file_list = [
    225                 'scaling_min_freq', 'scaling_max_freq', 'scaling_setspeed'
    226             ]
    227 
    228         for fname in file_list:
    229             self.__write_file(fname, str(frequency))
    230 
    231     def disable_boost(self):
    232         """Disable boost.
    233 
    234         Note, boost is NOT a per-cpu parameter,
    235           /sys/device/system/cpu/cpufreq/boost
    236 
    237         So code below would unnecessarily disable it per-cpu but that should not
    238         cause any issues.
    239         """
    240         logging.debug('Disable boost')
    241         self.__write_file('../../cpufreq/boost', '0')
    242 
    243     def enable_boost(self):
    244         """Enable boost.
    245 
    246         Note, boost is NOT a per-cpu parameter,
    247           /sys/device/system/cpu/cpufreq/boost
    248 
    249         So code below would unnecessarily enable it per-cpu but that should not
    250         cause any issues.
    251         """
    252         logging.debug('Enable boost')
    253         self.__write_file('../../cpufreq/boost', '1')
    254