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, sys, time 6 from autotest_lib.client.common_lib import error 7 from autotest_lib.server import autotest 8 from autotest_lib.server import hosts 9 from autotest_lib.server import test 10 11 class hardware_StorageStress(test.test): 12 """ 13 Integrity stress test for storage device 14 """ 15 version = 1 16 17 _HOURS_IN_SEC = 3600 18 # Define default value for the test case 19 _TEST_GAP = 60 # 1 min 20 _TEST_DURATION = 12 * _HOURS_IN_SEC 21 _SUSPEND_DURATION = _HOURS_IN_SEC 22 _FIO_REQUIREMENT_FILE = '8k_async_randwrite' 23 _FIO_WRITE_FLAGS = [] 24 _FIO_VERIFY_FLAGS = ['--verifyonly'] 25 26 def run_once(self, client_ip, gap=_TEST_GAP, duration=_TEST_DURATION, 27 power_command='reboot', storage_test_command='integrity', 28 suspend_duration=_SUSPEND_DURATION, storage_test_argument=''): 29 """ 30 Run the Storage stress test 31 Use hardwareStorageFio to run some test_command repeatedly for a long 32 time. Between each iteration of test command, run power command such as 33 reboot or suspend. 34 35 @param client_ip: string of client's ip address (required) 36 @param gap: gap between each test (second) default = 1 min 37 @param duration: duration to run test (second) default = 12 hours 38 @param power_command: command to do between each test Command 39 possible command: reboot / suspend / nothing 40 @param storage_test_command: FIO command to run 41 - integrity: Check data integrity 42 - full_write: Check performance consistency 43 for full disk write. Use argument 44 to determine which disk to write 45 @param suspend_duration: if power_command is suspend, how long the DUT 46 is suspended. 47 """ 48 49 # init test 50 if not client_ip: 51 error.TestError("Must provide client's IP address to test") 52 53 self._client = hosts.create_host(client_ip) 54 self._client_at = autotest.Autotest(self._client) 55 self._results = {} 56 self._suspend_duration = suspend_duration 57 58 # parse power command 59 if power_command == 'nothing': 60 power_func = self._do_nothing 61 elif power_command == 'reboot': 62 power_func = self._do_reboot 63 elif power_command == 'suspend': 64 power_func = self._do_suspend 65 else: 66 raise error.TestFail( 67 'Test failed with error: Invalid power command') 68 69 # Test is doing a lot of disk activity, monitor disk data at each iteration. 70 self.job.add_sysinfo_logfile('/var/log/storage_info.txt', on_every_test=True) 71 72 # parse test command 73 if storage_test_command == 'integrity': 74 setup_func = self._write_data 75 loop_func = self._verify_data 76 elif storage_test_command == 'full_write': 77 setup_func = self._do_nothing 78 loop_func = self._full_disk_write 79 # Do at least 2 soak runs. Given the absolute minimum of a loop is 80 # around 1h, duration should be at least 1h. 81 self._soak_time = min(self._TEST_DURATION, duration / 4) 82 else: 83 raise error.TestFail('Test failed with error: Invalid test command') 84 85 # init statistic variable 86 min_time_per_loop = sys.maxsize 87 max_time_per_loop = 0 88 all_loop_time = 0 89 avr_time_per_loop = 0 90 self._loop_count = 0 91 setup_func() 92 93 start_time = time.time() 94 95 while time.time() - start_time < duration: 96 # sleep 97 time.sleep(gap) 98 99 self._loop_count += 1 100 101 # do power command & verify data & calculate time 102 loop_start_time = time.time() 103 power_func() 104 loop_func() 105 loop_time = time.time() - loop_start_time 106 107 # update statistic 108 all_loop_time += loop_time 109 min_time_per_loop = min(loop_time, min_time_per_loop) 110 max_time_per_loop = max(loop_time, max_time_per_loop) 111 112 if self._loop_count > 0: 113 avr_time_per_loop = all_loop_time / self._loop_count 114 115 logging.info(str('check data count: %d' % self._loop_count)) 116 117 # report result 118 self.write_perf_keyval({'loop_count':self._loop_count}) 119 self.write_perf_keyval({'min_time_per_loop':min_time_per_loop}) 120 self.write_perf_keyval({'max_time_per_loop':max_time_per_loop}) 121 self.write_perf_keyval({'avr_time_per_loop':avr_time_per_loop}) 122 123 def _do_nothing(self): 124 pass 125 126 def _do_reboot(self): 127 """ 128 Reboot host machine 129 """ 130 self._client.reboot() 131 132 def _do_suspend(self): 133 """ 134 Suspend host machine 135 """ 136 self._client.suspend(suspend_time=self._suspend_duration) 137 138 def _write_data(self): 139 """ 140 Write test data to host using hardware_StorageFio 141 """ 142 logging.info('_write_data') 143 self._client_at.run_test('hardware_StorageFio', 144 check_client_result=True, disable_sysinfo=True, wait=0, 145 tag='%s_%d' % ('write_data', self._loop_count), 146 requirements=[(self._FIO_REQUIREMENT_FILE, self._FIO_WRITE_FLAGS)]) 147 148 def _verify_data(self): 149 """ 150 Verify test data using hardware_StorageFio 151 """ 152 logging.info(str('_verify_data #%d' % self._loop_count)) 153 self._client_at.run_test('hardware_StorageFio', 154 check_client_result=True, disable_sysinfo=True, wait=0, 155 tag='%s_%d' % ('verify_data', self._loop_count), 156 requirements=[(self._FIO_REQUIREMENT_FILE, self._FIO_VERIFY_FLAGS)]) 157 158 def _full_disk_write(self): 159 """ 160 Do the root device full area write and report performance 161 Write random pattern for few hours, then do a write and a verify, 162 noting the latency. 163 """ 164 logging.info(str('_full_disk_write #%d' % self._loop_count)) 165 166 # use the default requirement that write different pattern arround. 167 self._client_at.run_test('hardware_StorageFio', 168 check_client_result=True, 169 disable_sysinfo=True, 170 tag='%s_%d' % ('soak', self._loop_count), 171 requirements=[('64k_stress', [])], 172 time_length=self._soak_time) 173 174 self._client_at.run_test('hardware_StorageFio', 175 check_client_result=True, 176 disable_sysinfo=True, 177 tag='%s_%d' % ('surf', self._loop_count), 178 requirements=[('surfing', [])], 179 time_length=self._soak_time) 180 181 self._client_at.run_test('hardware_StorageFio', 182 check_client_result=True, 183 disable_sysinfo=True, 184 tag='%s_%d' % ('integrity', self._loop_count), 185 wait=0, integrity=True) 186 187 self._client_at.run_test('hardware_StorageWearoutDetect', 188 tag='%s_%d' % ('wearout', self._loop_count), 189 wait=0, use_cached_result=False) 190 # No checkout for wearout, to test device pass their limits. 191