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