| # Copyright (c) 2014 The Chromium 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 |
| |
| from autotest_lib.client.bin import test, utils |
| from autotest_lib.client.common_lib import error |
| |
| class kernel_Delay(test.test): |
| """ |
| Test to ensure that udelay() delays at least as long as requested |
| (as compared to ktime()). |
| |
| Test a variety of delays at mininmum and maximum cpu frequencies. |
| |
| """ |
| version = 1 |
| |
| # Module not present prior to 3.8. From 4.4 on, module renamed. |
| MIN_KERNEL_VER = '3.8' |
| OLD_MODULE_NAME = 'udelay_test' |
| NEW_KERNEL_VER = '4.4' |
| NEW_MODULE_NAME = 'test_udelay' |
| |
| UDELAY_PATH = '/sys/kernel/debug/udelay_test' |
| QUIET_GOVERNOR_PATH = '/sys/devices/system/cpu/cpuquiet/current_governor' |
| GOVERNOR_GLOB = '/sys/devices/system/cpu/cpu*/cpufreq/scaling_governor' |
| SETSPEED_GLOB = '/sys/devices/system/cpu/cpu*/cpufreq/scaling_setspeed' |
| CUR_FREQ_GLOB = '/sys/devices/system/cpu/cpu*/cpufreq/cpuinfo_cur_freq' |
| CPUFREQ_AVAIL_GOVERNORS_PATH = ( |
| '/sys/devices/system/cpu/cpu0/cpufreq/' |
| 'scaling_available_governors') |
| CPUFREQ_AVAIL_FREQS_PATH = ( |
| '/sys/devices/system/cpu/cpu0/cpufreq/' |
| 'scaling_available_frequencies') |
| |
| # Test a variety of delays |
| # 1..200, 200..500 (by 10), 500..2000 (by 100) |
| DELAYS = range(1, 200) + range(200, 500, 10) + range(500, 2001, 100) |
| ITERATIONS = 100 |
| |
| _governor_paths = [] |
| _setspeed_paths = [] |
| _cur_freq_paths = [] |
| |
| def _set_file(self, contents, filename): |
| """ |
| Write a string to a file. |
| |
| @param contents: the contents to write to the file |
| @param filename: the filename to use |
| |
| """ |
| logging.debug('setting %s to %s', filename, contents) |
| with open(filename, 'w') as f: |
| f.write(contents) |
| |
| |
| def _get_file(self, filename): |
| """ |
| Read a string from a file. |
| |
| @returns: the contents of the file (string) |
| |
| """ |
| with open(filename, 'r') as f: |
| return f.read() |
| |
| |
| def _get_freqs(self): |
| """ |
| Get the current CPU frequencies. |
| |
| @returns: the CPU frequencies of each CPU (list of int) |
| |
| """ |
| return [int(self._get_file(p)) for p in self._cur_freq_paths] |
| |
| |
| def _get_freqs_string(self): |
| """ |
| Get the current CPU frequencies. |
| |
| @returns: the CPU frequencies of each CPU (string) |
| |
| """ |
| return ' '.join(str(x) for x in self._get_freqs()) |
| |
| |
| def _get_governors(self): |
| """ |
| Get the current CPU governors. |
| |
| @returns: the CPU governors of each CPU (list of string) |
| |
| """ |
| return [self._get_file(p).rstrip() for p in self._governor_paths] |
| |
| |
| def _get_quiet_governor(self): |
| """ |
| Get the current CPU quiet governor. |
| |
| @returns: the CPU quiet governor or None if it does not exist (string) |
| |
| """ |
| if os.path.isfile(self.QUIET_GOVERNOR_PATH): |
| return self._get_file(self.QUIET_GOVERNOR_PATH).rstrip() |
| else: |
| return None |
| |
| |
| def _reset_freq(self, initial_governors, initial_quiet_governor): |
| """ |
| Unlimit the CPU frequency. |
| |
| @param initial_governors: list of initial governors to reset state to |
| @param initial_quiet_governor: initial quiet governor to reset state to |
| |
| """ |
| for p, g in zip(self._governor_paths, initial_governors): |
| self._set_file(g, p) |
| if initial_quiet_governor and os.path.isfile(self.QUIET_GOVERNOR_PATH): |
| self._set_file(initial_quiet_governor, self.QUIET_GOVERNOR_PATH) |
| |
| |
| def _set_freq(self, freq): |
| """ |
| Set the CPU frequency. |
| |
| @param freq: desired CPU frequency |
| |
| """ |
| # Prevent CPUs from going up and down during the test if the option |
| # is available. |
| if os.path.isfile(self.QUIET_GOVERNOR_PATH): |
| logging.info('changing to userspace cpuquiet governor'); |
| self._set_file('userspace', self.QUIET_GOVERNOR_PATH) |
| |
| for p in self._governor_paths: |
| self._set_file('userspace', p) |
| for p in self._setspeed_paths: |
| self._set_file(str(freq), p) |
| logging.info( |
| 'cpu frequencies set to %s with userspace governor', |
| self._get_freqs_string()) |
| self._check_freq(freq) |
| |
| |
| def _check_freq(self, freq): |
| """ |
| Check the CPU frequencies are set as requested. |
| |
| @param freq: desired CPU frequency |
| |
| """ |
| for p in self._governor_paths: |
| governor = self._get_file(p).rstrip() |
| if governor != 'userspace': |
| raise error.TestFail('governor changed from userspace to %s' % ( |
| governor)) |
| for p in self._setspeed_paths: |
| speed = int(self._get_file(p)) |
| if speed != freq: |
| raise error.TestFail('setspeed changed from %s to %s' % ( |
| freq, speed)) |
| freqs = self._get_freqs() |
| for f in freqs: |
| if f != freq: |
| raise error.TestFail('frequency set to %s instead of %s' % ( |
| f, freq)) |
| |
| |
| def _test_udelay(self, usecs): |
| """ |
| Test udelay() for a given amount of time. |
| |
| @param usecs: number of usecs to delay for each iteration |
| |
| """ |
| self._set_file('%d %d' % (usecs, self.ITERATIONS), self.UDELAY_PATH) |
| with open(self.UDELAY_PATH, 'r') as f: |
| for line in f: |
| line = line.rstrip() |
| logging.info('result: %s', line) |
| if 'FAIL' in line: |
| raise error.TestFail('udelay failed: %s' % line) |
| |
| def _test_all_delays(self): |
| """ |
| Test udelay() over all configured delays. |
| |
| """ |
| for usecs in self.DELAYS: |
| self._test_udelay(usecs) |
| |
| def _test_userspace(self): |
| """ |
| Test udelay() using userspace governor. |
| |
| """ |
| logging.info('testing with userspace governor') |
| with open(self.CPUFREQ_AVAIL_FREQS_PATH, 'r') as f: |
| available_freqs = [int(x) for x in f.readline().split()] |
| |
| max_freq = max(available_freqs) |
| min_freq = min(available_freqs) |
| logging.info('cpu frequency max %d min %d', max_freq, min_freq) |
| |
| freqs = [ min_freq, max_freq ] |
| for freq in freqs: |
| self._set_freq(freq) |
| self._test_all_delays() |
| self._check_freq(freq) |
| |
| def run_once(self): |
| kernel_ver = os.uname()[2] |
| if utils.compare_versions(kernel_ver, self.MIN_KERNEL_VER) < 0: |
| logging.info( |
| 'skipping test: old kernel %s (min %s) missing module %s', |
| kernel_ver, self.MIN_KERNEL_VER, self.OLD_MODULE_NAME) |
| return |
| |
| if utils.compare_versions(kernel_ver, self.NEW_KERNEL_VER) < 0: |
| module_name = self.OLD_MODULE_NAME |
| else: |
| module_name = self.NEW_MODULE_NAME |
| |
| utils.load_module(module_name) |
| |
| self._governor_paths = glob.glob(self.GOVERNOR_GLOB) |
| self._setspeed_paths = glob.glob(self.SETSPEED_GLOB) |
| self._cur_freq_paths = glob.glob(self.CUR_FREQ_GLOB) |
| initial_governors = self._get_governors() |
| initial_quiet_governor = self._get_quiet_governor() |
| |
| with open(self.CPUFREQ_AVAIL_GOVERNORS_PATH, 'r') as f: |
| available_governors = set(f.readline().split()) |
| logging.info('governors: %s', ' '.join(available_governors)) |
| |
| try: |
| if 'userspace' in available_governors: |
| self._test_userspace() |
| else: |
| logging.warning('testing with existing governor') |
| self._test_all_delays() |
| finally: |
| self._reset_freq(initial_governors, initial_quiet_governor) |
| utils.unload_module(module_name) |