• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright (c) 2013 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
5import logging, numpy, random, time
6
7from autotest_lib.client.bin import test, utils
8from autotest_lib.client.common_lib import error
9from autotest_lib.client.cros import power_suspend, sys_power
10
11
12class power_SuspendStress(test.test):
13    version = 1
14
15    def initialize(self, duration, idle=False, init_delay=0, min_suspend=0,
16                   min_resume=0, interface=None):
17        """
18        Entry point.
19
20        @param duration: total run time of the test
21        @param idle: use sys_power.idle_suspend method.
22                (use with dummy_IdleSuspend)
23        @param init_delay: wait this many seconds before starting the test to
24                give parallel tests time to get started
25        @param min_suspend: suspend durations will be chosen randomly out of
26                the interval between min_suspend and min_suspend + 3 seconds.
27        @param min_resume: minimal time in seconds between suspends.
28        @param interface: network interface used to connect to the server. If
29                specified, will reboot the DUT if the interface is not coming
30                back after suspend.
31        """
32        self._duration = duration
33        self._init_delay = init_delay
34        self._min_suspend = min_suspend
35        self._min_resume = min_resume
36        self._interface = interface
37        self._method = sys_power.idle_suspend if idle else sys_power.do_suspend
38
39
40    def run_once(self):
41        time.sleep(self._init_delay)
42        self._suspender = power_suspend.Suspender(
43                self.resultsdir, method=self._method)
44        timeout = time.time() + self._duration
45        while time.time() < timeout:
46            time.sleep(self._min_resume + random.randint(0, 3))
47            # Check the network interface to the caller is still available
48            if self._interface:
49                link_status = None
50                try:
51                    with open('/sys/class/net/' + self._interface +
52                              '/operstate') as link_file:
53                        link_status = link_file.readline().strip()
54                except:
55                    pass
56                if link_status != 'up':
57                    logging.error('Link to the server gone, reboot')
58                    utils.system('reboot')
59
60            self._suspender.suspend(random.randint(0, 3) + self._min_suspend)
61
62
63    def postprocess_iteration(self):
64        if self._suspender.successes:
65            keyvals = {'suspend_iterations': len(self._suspender.successes)}
66            for key in self._suspender.successes[0]:
67                values = [result[key] for result in self._suspender.successes]
68                keyvals[key + '_mean'] = numpy.mean(values)
69                keyvals[key + '_stddev'] = numpy.std(values)
70                keyvals[key + '_min'] = numpy.amin(values)
71                keyvals[key + '_max'] = numpy.amax(values)
72            self.write_perf_keyval(keyvals)
73        if self._suspender.failures:
74            total = len(self._suspender.failures)
75            iterations = len(self._suspender.successes) + total
76            timeout = kernel = firmware = spurious = 0
77            for failure in self._suspender.failures:
78                if type(failure) is sys_power.SuspendTimeout: timeout += 1
79                if type(failure) is sys_power.KernelError: kernel += 1
80                if type(failure) is sys_power.FirmwareError: firmware += 1
81                if type(failure) is sys_power.SpuriousWakeupError: spurious += 1
82            if total == kernel + timeout:
83                raise error.TestWarn('%d non-fatal suspend failures in %d '
84                        'iterations (%d timeouts, %d kernel warnings)' %
85                        (total, iterations, timeout, kernel))
86            if total == 1:
87                # just throw it as is, makes aggregation on dashboards easier
88                raise self._suspender.failures[0]
89            raise error.TestFail('%d suspend failures in %d iterations (%d '
90                    'timeouts, %d kernel warnings, %d firmware errors, %d '
91                    'spurious wakeups)' %
92                    (total, iterations, timeout, kernel, firmware, spurious))
93
94
95    def cleanup(self):
96        """
97        Clean this up before we wait ages for all the log copying to finish...
98        """
99        self._suspender.finalize()
100