Home | History | Annotate | Download | only in power_SuspendStress
      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 
      5 import logging, numpy, random, time
      6 
      7 from autotest_lib.client.bin import test, utils
      8 from autotest_lib.client.common_lib import error
      9 from autotest_lib.client.cros import power_suspend, sys_power
     10 
     11 
     12 class 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