• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright (c) 2014 The Chromium 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
6import logging
7import os
8
9from autotest_lib.client.bin import test, utils
10from autotest_lib.client.common_lib import error
11
12class kernel_Delay(test.test):
13    """
14    Test to ensure that udelay() delays at least as long as requested
15    (as compared to ktime()).
16
17    Test a variety of delays at mininmum and maximum cpu frequencies.
18
19    """
20    version = 1
21
22    # Module not present prior to 3.8.  From 4.4 on, module renamed.
23    MIN_KERNEL_VER = '3.8'
24    OLD_MODULE_NAME = 'udelay_test'
25    NEW_KERNEL_VER = '4.4'
26    NEW_MODULE_NAME = 'test_udelay'
27
28    UDELAY_PATH = '/sys/kernel/debug/udelay_test'
29    QUIET_GOVERNOR_PATH = '/sys/devices/system/cpu/cpuquiet/current_governor'
30    GOVERNOR_GLOB = '/sys/devices/system/cpu/cpu*/cpufreq/scaling_governor'
31    SETSPEED_GLOB = '/sys/devices/system/cpu/cpu*/cpufreq/scaling_setspeed'
32    CUR_FREQ_GLOB = '/sys/devices/system/cpu/cpu*/cpufreq/cpuinfo_cur_freq'
33    CPUFREQ_AVAIL_GOVERNORS_PATH = (
34            '/sys/devices/system/cpu/cpu0/cpufreq/'
35            'scaling_available_governors')
36    CPUFREQ_AVAIL_FREQS_PATH = (
37            '/sys/devices/system/cpu/cpu0/cpufreq/'
38            'scaling_available_frequencies')
39
40    # Test a variety of delays
41    # 1..200, 200..500 (by 10), 500..2000 (by 100)
42    DELAYS = range(1, 200) + range(200, 500, 10) + range(500, 2001, 100)
43    ITERATIONS = 100
44
45    _governor_paths = []
46    _setspeed_paths = []
47    _cur_freq_paths = []
48
49    def _set_file(self, contents, filename):
50        """
51        Write a string to a file.
52
53        @param contents: the contents to write to the file
54        @param filename: the filename to use
55
56        """
57        logging.debug('setting %s to %s', filename, contents)
58        with open(filename, 'w') as f:
59            f.write(contents)
60
61
62    def _get_file(self, filename):
63        """
64        Read a string from a file.
65
66        @returns: the contents of the file (string)
67
68        """
69        with open(filename, 'r') as f:
70            return f.read()
71
72
73    def _get_freqs(self):
74        """
75        Get the current CPU frequencies.
76
77        @returns: the CPU frequencies of each CPU (list of int)
78
79        """
80        return [int(self._get_file(p)) for p in self._cur_freq_paths]
81
82
83    def _get_freqs_string(self):
84        """
85        Get the current CPU frequencies.
86
87        @returns: the CPU frequencies of each CPU (string)
88
89        """
90        return ' '.join(str(x) for x in self._get_freqs())
91
92
93    def _get_governors(self):
94        """
95        Get the current CPU governors.
96
97        @returns: the CPU governors of each CPU (list of string)
98
99        """
100        return [self._get_file(p).rstrip() for p in self._governor_paths]
101
102
103    def _get_quiet_governor(self):
104        """
105        Get the current CPU quiet governor.
106
107        @returns: the CPU quiet governor or None if it does not exist (string)
108
109        """
110        if os.path.isfile(self.QUIET_GOVERNOR_PATH):
111            return self._get_file(self.QUIET_GOVERNOR_PATH).rstrip()
112        else:
113            return None
114
115
116    def _reset_freq(self, initial_governors, initial_quiet_governor):
117        """
118        Unlimit the CPU frequency.
119
120        @param initial_governors: list of initial governors to reset state to
121        @param initial_quiet_governor: initial quiet governor to reset state to
122
123        """
124        for p, g in zip(self._governor_paths, initial_governors):
125            self._set_file(g, p)
126        if initial_quiet_governor and os.path.isfile(self.QUIET_GOVERNOR_PATH):
127            self._set_file(initial_quiet_governor, self.QUIET_GOVERNOR_PATH)
128
129
130    def _set_freq(self, freq):
131        """
132        Set the CPU frequency.
133
134        @param freq: desired CPU frequency
135
136        """
137        # Prevent CPUs from going up and down during the test if the option
138        # is available.
139        if os.path.isfile(self.QUIET_GOVERNOR_PATH):
140            logging.info('changing to userspace cpuquiet governor');
141            self._set_file('userspace', self.QUIET_GOVERNOR_PATH)
142
143        for p in self._governor_paths:
144            self._set_file('userspace', p)
145        for p in self._setspeed_paths:
146            self._set_file(str(freq), p)
147        logging.info(
148                'cpu frequencies set to %s with userspace governor',
149                self._get_freqs_string())
150        self._check_freq(freq)
151
152
153    def _check_freq(self, freq):
154        """
155        Check the CPU frequencies are set as requested.
156
157        @param freq: desired CPU frequency
158
159        """
160        for p in self._governor_paths:
161            governor = self._get_file(p).rstrip()
162            if governor != 'userspace':
163                raise error.TestFail('governor changed from userspace to %s' % (
164                        governor))
165        for p in self._setspeed_paths:
166            speed = int(self._get_file(p))
167            if speed != freq:
168                raise error.TestFail('setspeed changed from %s to %s' % (
169                        freq, speed))
170        freqs = self._get_freqs()
171        for f in freqs:
172            if f != freq:
173                raise error.TestFail('frequency set to %s instead of %s' % (
174                        f, freq))
175
176
177    def _test_udelay(self, usecs):
178        """
179        Test udelay() for a given amount of time.
180
181        @param usecs: number of usecs to delay for each iteration
182
183        """
184        self._set_file('%d %d' % (usecs, self.ITERATIONS), self.UDELAY_PATH)
185        with open(self.UDELAY_PATH, 'r') as f:
186            for line in f:
187                line = line.rstrip()
188                logging.info('result: %s', line)
189                if 'FAIL' in line:
190                    raise error.TestFail('udelay failed: %s' % line)
191
192    def _test_all_delays(self):
193        """
194        Test udelay() over all configured delays.
195
196        """
197        for usecs in self.DELAYS:
198            self._test_udelay(usecs)
199
200    def _test_userspace(self):
201        """
202        Test udelay() using userspace governor.
203
204        """
205        logging.info('testing with userspace governor')
206        with open(self.CPUFREQ_AVAIL_FREQS_PATH, 'r') as f:
207            available_freqs = [int(x) for x in f.readline().split()]
208
209        max_freq = max(available_freqs)
210        min_freq = min(available_freqs)
211        logging.info('cpu frequency max %d min %d', max_freq, min_freq)
212
213        freqs = [ min_freq, max_freq ]
214        for freq in freqs:
215            self._set_freq(freq)
216            self._test_all_delays()
217            self._check_freq(freq)
218
219    def run_once(self):
220        kernel_ver = os.uname()[2]
221        if utils.compare_versions(kernel_ver, self.MIN_KERNEL_VER) < 0:
222            logging.info(
223                    'skipping test: old kernel %s (min %s) missing module %s',
224                    kernel_ver, self.MIN_KERNEL_VER, self.OLD_MODULE_NAME)
225            return
226
227        if utils.compare_versions(kernel_ver, self.NEW_KERNEL_VER) < 0:
228            module_name = self.OLD_MODULE_NAME
229        else:
230            module_name = self.NEW_MODULE_NAME
231
232        utils.load_module(module_name)
233
234        self._governor_paths = glob.glob(self.GOVERNOR_GLOB)
235        self._setspeed_paths = glob.glob(self.SETSPEED_GLOB)
236        self._cur_freq_paths = glob.glob(self.CUR_FREQ_GLOB)
237        initial_governors = self._get_governors()
238        initial_quiet_governor = self._get_quiet_governor()
239
240        with open(self.CPUFREQ_AVAIL_GOVERNORS_PATH, 'r') as f:
241            available_governors = set(f.readline().split())
242        logging.info('governors: %s', ' '.join(available_governors))
243
244        try:
245            if 'userspace' in available_governors:
246                self._test_userspace()
247            else:
248                logging.warning('testing with existing governor')
249                self._test_all_delays()
250        finally:
251            self._reset_freq(initial_governors, initial_quiet_governor)
252            utils.unload_module(module_name)
253