Puthikorn Voravootivat | 8c1f434 | 2013-10-24 14:18:41 -0700 | [diff] [blame] | 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 | |
Gwendal Grignou | 14bd4ba | 2014-06-04 16:38:35 -0700 | [diff] [blame] | 5 | import logging, sys, time |
Puthikorn Voravootivat | 8c1f434 | 2013-10-24 14:18:41 -0700 | [diff] [blame] | 6 | from autotest_lib.client.common_lib import error |
| 7 | from autotest_lib.server import autotest |
| 8 | from autotest_lib.server import hosts |
Puthikorn Voravootivat | 7334d69 | 2013-10-29 16:55:37 -0700 | [diff] [blame] | 9 | from autotest_lib.server import test |
Puthikorn Voravootivat | 8c1f434 | 2013-10-24 14:18:41 -0700 | [diff] [blame] | 10 | |
| 11 | class hardware_StorageStress(test.test): |
| 12 | """ |
| 13 | Integrity stress test for storage device |
| 14 | """ |
| 15 | version = 1 |
| 16 | |
Gwendal Grignou | 14bd4ba | 2014-06-04 16:38:35 -0700 | [diff] [blame] | 17 | _HOURS_IN_SEC = 3600 |
Puthikorn Voravootivat | 8c1f434 | 2013-10-24 14:18:41 -0700 | [diff] [blame] | 18 | # Define default value for the test case |
| 19 | _TEST_GAP = 60 # 1 min |
Gwendal Grignou | 14bd4ba | 2014-06-04 16:38:35 -0700 | [diff] [blame] | 20 | _TEST_DURATION = 12 * _HOURS_IN_SEC |
| 21 | _SUSPEND_DURATION = _HOURS_IN_SEC |
Puthikorn Voravootivat | 8c1f434 | 2013-10-24 14:18:41 -0700 | [diff] [blame] | 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, |
Puthikorn Voravootivat | 5d98386 | 2013-10-29 17:50:19 -0700 | [diff] [blame] | 27 | power_command='reboot', storage_test_command='integrity', |
Gwendal Grignou | 7a61d2f | 2014-05-23 11:05:51 -0700 | [diff] [blame] | 28 | suspend_duration=_SUSPEND_DURATION, storage_test_argument=''): |
Puthikorn Voravootivat | 8c1f434 | 2013-10-24 14:18:41 -0700 | [diff] [blame] | 29 | """ |
Puthikorn Voravootivat | 5961788 | 2013-10-29 17:31:37 -0700 | [diff] [blame] | 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. |
Puthikorn Voravootivat | 8c1f434 | 2013-10-24 14:18:41 -0700 | [diff] [blame] | 34 | |
Puthikorn Voravootivat | 5961788 | 2013-10-29 17:31:37 -0700 | [diff] [blame] | 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 |
Puthikorn Voravootivat | 5d98386 | 2013-10-29 17:50:19 -0700 | [diff] [blame] | 40 | @param storage_test_command: FIO command to run |
Puthikorn Voravootivat | 5961788 | 2013-10-29 17:31:37 -0700 | [diff] [blame] | 41 | - integrity: Check data integrity |
Puthikorn Voravootivat | 5d98386 | 2013-10-29 17:50:19 -0700 | [diff] [blame] | 42 | - full_write: Check performance consistency |
| 43 | for full disk write. Use argument |
| 44 | to determine which disk to write |
Gwendal Grignou | 7a61d2f | 2014-05-23 11:05:51 -0700 | [diff] [blame] | 45 | @param suspend_duration: if power_command is suspend, how long the DUT |
| 46 | is suspended. |
Puthikorn Voravootivat | 8c1f434 | 2013-10-24 14:18:41 -0700 | [diff] [blame] | 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 = {} |
Gwendal Grignou | 7a61d2f | 2014-05-23 11:05:51 -0700 | [diff] [blame] | 56 | self._suspend_duration = suspend_duration |
Puthikorn Voravootivat | 8c1f434 | 2013-10-24 14:18:41 -0700 | [diff] [blame] | 57 | |
Puthikorn Voravootivat | 5961788 | 2013-10-29 17:31:37 -0700 | [diff] [blame] | 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 |
Puthikorn Voravootivat | 8c1f434 | 2013-10-24 14:18:41 -0700 | [diff] [blame] | 65 | else: |
Puthikorn Voravootivat | 5961788 | 2013-10-29 17:31:37 -0700 | [diff] [blame] | 66 | raise error.TestFail( |
| 67 | 'Test failed with error: Invalid power command') |
Puthikorn Voravootivat | 8c1f434 | 2013-10-24 14:18:41 -0700 | [diff] [blame] | 68 | |
Gwendal Grignou | 96652f0 | 2015-11-04 10:24:11 -0800 | [diff] [blame] | 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 | |
Puthikorn Voravootivat | 5961788 | 2013-10-29 17:31:37 -0700 | [diff] [blame] | 72 | # parse test command |
Puthikorn Voravootivat | 5d98386 | 2013-10-29 17:50:19 -0700 | [diff] [blame] | 73 | if storage_test_command == 'integrity': |
Puthikorn Voravootivat | 5961788 | 2013-10-29 17:31:37 -0700 | [diff] [blame] | 74 | setup_func = self._write_data |
| 75 | loop_func = self._verify_data |
Puthikorn Voravootivat | 5d98386 | 2013-10-29 17:50:19 -0700 | [diff] [blame] | 76 | elif storage_test_command == 'full_write': |
| 77 | setup_func = self._do_nothing |
Gwendal Grignou | 14bd4ba | 2014-06-04 16:38:35 -0700 | [diff] [blame] | 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) |
Puthikorn Voravootivat | 5961788 | 2013-10-29 17:31:37 -0700 | [diff] [blame] | 82 | else: |
| 83 | raise error.TestFail('Test failed with error: Invalid test command') |
| 84 | |
Puthikorn Voravootivat | 8c1f434 | 2013-10-24 14:18:41 -0700 | [diff] [blame] | 85 | # init statistic variable |
Gwendal Grignou | 14bd4ba | 2014-06-04 16:38:35 -0700 | [diff] [blame] | 86 | min_time_per_loop = sys.maxsize |
Puthikorn Voravootivat | 8c1f434 | 2013-10-24 14:18:41 -0700 | [diff] [blame] | 87 | max_time_per_loop = 0 |
| 88 | all_loop_time = 0 |
| 89 | avr_time_per_loop = 0 |
Puthikorn Voravootivat | 5961788 | 2013-10-29 17:31:37 -0700 | [diff] [blame] | 90 | self._loop_count = 0 |
Gwendal Grignou | 72e5412 | 2014-06-22 10:58:21 -0700 | [diff] [blame] | 91 | setup_func() |
Puthikorn Voravootivat | 8c1f434 | 2013-10-24 14:18:41 -0700 | [diff] [blame] | 92 | |
Gwendal Grignou | 7a61d2f | 2014-05-23 11:05:51 -0700 | [diff] [blame] | 93 | start_time = time.time() |
| 94 | |
Puthikorn Voravootivat | 8c1f434 | 2013-10-24 14:18:41 -0700 | [diff] [blame] | 95 | while time.time() - start_time < duration: |
| 96 | # sleep |
| 97 | time.sleep(gap) |
| 98 | |
Puthikorn Voravootivat | 5961788 | 2013-10-29 17:31:37 -0700 | [diff] [blame] | 99 | self._loop_count += 1 |
| 100 | |
Puthikorn Voravootivat | 8c1f434 | 2013-10-24 14:18:41 -0700 | [diff] [blame] | 101 | # do power command & verify data & calculate time |
| 102 | loop_start_time = time.time() |
Puthikorn Voravootivat | 5961788 | 2013-10-29 17:31:37 -0700 | [diff] [blame] | 103 | power_func() |
| 104 | loop_func() |
Puthikorn Voravootivat | 8c1f434 | 2013-10-24 14:18:41 -0700 | [diff] [blame] | 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 | |
Puthikorn Voravootivat | 5961788 | 2013-10-29 17:31:37 -0700 | [diff] [blame] | 112 | if self._loop_count > 0: |
| 113 | avr_time_per_loop = all_loop_time / self._loop_count |
Puthikorn Voravootivat | 8c1f434 | 2013-10-24 14:18:41 -0700 | [diff] [blame] | 114 | |
Puthikorn Voravootivat | 5961788 | 2013-10-29 17:31:37 -0700 | [diff] [blame] | 115 | logging.info(str('check data count: %d' % self._loop_count)) |
Puthikorn Voravootivat | 8c1f434 | 2013-10-24 14:18:41 -0700 | [diff] [blame] | 116 | |
| 117 | # report result |
Puthikorn Voravootivat | 5961788 | 2013-10-29 17:31:37 -0700 | [diff] [blame] | 118 | self.write_perf_keyval({'loop_count':self._loop_count}) |
Puthikorn Voravootivat | 8c1f434 | 2013-10-24 14:18:41 -0700 | [diff] [blame] | 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 | |
Puthikorn Voravootivat | 5961788 | 2013-10-29 17:31:37 -0700 | [diff] [blame] | 123 | def _do_nothing(self): |
| 124 | pass |
| 125 | |
Puthikorn Voravootivat | 8c1f434 | 2013-10-24 14:18:41 -0700 | [diff] [blame] | 126 | def _do_reboot(self): |
| 127 | """ |
| 128 | Reboot host machine |
| 129 | """ |
Gwendal Grignou | 7a61d2f | 2014-05-23 11:05:51 -0700 | [diff] [blame] | 130 | self._client.reboot() |
Puthikorn Voravootivat | 8c1f434 | 2013-10-24 14:18:41 -0700 | [diff] [blame] | 131 | |
| 132 | def _do_suspend(self): |
| 133 | """ |
| 134 | Suspend host machine |
| 135 | """ |
Gwendal Grignou | 7a61d2f | 2014-05-23 11:05:51 -0700 | [diff] [blame] | 136 | self._client.suspend(suspend_time=self._suspend_duration) |
Puthikorn Voravootivat | 8c1f434 | 2013-10-24 14:18:41 -0700 | [diff] [blame] | 137 | |
Gwendal Grignou | 14bd4ba | 2014-06-04 16:38:35 -0700 | [diff] [blame] | 138 | @classmethod |
| 139 | def _check_client_test_result(cls, client): |
Puthikorn Voravootivat | 8c1f434 | 2013-10-24 14:18:41 -0700 | [diff] [blame] | 140 | """ |
| 141 | Check result of the client test. |
| 142 | Auto test will store results in the file named status. |
| 143 | We check that the second to last line in that file begin with 'END GOOD' |
| 144 | |
Gwendal Grignou | 14bd4ba | 2014-06-04 16:38:35 -0700 | [diff] [blame] | 145 | @ raise an error if test fails. |
Puthikorn Voravootivat | 8c1f434 | 2013-10-24 14:18:41 -0700 | [diff] [blame] | 146 | """ |
Puthikorn Voravootivat | 7334d69 | 2013-10-29 16:55:37 -0700 | [diff] [blame] | 147 | client_result_dir = '%s/results/default' % client.autodir |
| 148 | command = 'tail -2 %s/status | head -1' % client_result_dir |
| 149 | status = client.run(command).stdout.strip() |
Puthikorn Voravootivat | 8c1f434 | 2013-10-24 14:18:41 -0700 | [diff] [blame] | 150 | logging.info(status) |
Gwendal Grignou | 14bd4ba | 2014-06-04 16:38:35 -0700 | [diff] [blame] | 151 | if status[:8] != 'END GOOD': |
| 152 | raise error.TestFail('client in StorageStress failed.') |
| 153 | |
Puthikorn Voravootivat | 8c1f434 | 2013-10-24 14:18:41 -0700 | [diff] [blame] | 154 | |
Puthikorn Voravootivat | 8c1f434 | 2013-10-24 14:18:41 -0700 | [diff] [blame] | 155 | def _write_data(self): |
| 156 | """ |
| 157 | Write test data to host using hardware_StorageFio |
| 158 | """ |
| 159 | logging.info('_write_data') |
Gwendal Grignou | ae36712 | 2015-02-25 10:58:51 -0800 | [diff] [blame] | 160 | self._client_at.run_test('hardware_StorageFio', disable_sysinfo=True, |
| 161 | wait=0, tag='%s_%d' % ('write_data', self._loop_count), |
Gwendal Grignou | 14bd4ba | 2014-06-04 16:38:35 -0700 | [diff] [blame] | 162 | requirements=[(self._FIO_REQUIREMENT_FILE, self._FIO_WRITE_FLAGS)]) |
| 163 | self._check_client_test_result(self._client) |
Puthikorn Voravootivat | 8c1f434 | 2013-10-24 14:18:41 -0700 | [diff] [blame] | 164 | |
| 165 | def _verify_data(self): |
| 166 | """ |
Gwendal Grignou | 14bd4ba | 2014-06-04 16:38:35 -0700 | [diff] [blame] | 167 | Verify test data using hardware_StorageFio |
Puthikorn Voravootivat | 8c1f434 | 2013-10-24 14:18:41 -0700 | [diff] [blame] | 168 | """ |
Puthikorn Voravootivat | 5961788 | 2013-10-29 17:31:37 -0700 | [diff] [blame] | 169 | logging.info(str('_verify_data #%d' % self._loop_count)) |
Gwendal Grignou | ae36712 | 2015-02-25 10:58:51 -0800 | [diff] [blame] | 170 | self._client_at.run_test('hardware_StorageFio', disable_sysinfo=True, |
| 171 | wait=0, tag='%s_%d' % ('verify_data', self._loop_count), |
Gwendal Grignou | 14bd4ba | 2014-06-04 16:38:35 -0700 | [diff] [blame] | 172 | requirements=[(self._FIO_REQUIREMENT_FILE, self._FIO_VERIFY_FLAGS)]) |
| 173 | self._check_client_test_result(self._client) |
Puthikorn Voravootivat | 5d98386 | 2013-10-29 17:50:19 -0700 | [diff] [blame] | 174 | |
Gwendal Grignou | 14bd4ba | 2014-06-04 16:38:35 -0700 | [diff] [blame] | 175 | def _full_disk_write(self): |
Puthikorn Voravootivat | 5d98386 | 2013-10-29 17:50:19 -0700 | [diff] [blame] | 176 | """ |
| 177 | Do the root device full area write and report performance |
Gwendal Grignou | 14bd4ba | 2014-06-04 16:38:35 -0700 | [diff] [blame] | 178 | Write random pattern for few hours, then do a write and a verify, |
| 179 | noting the latency. |
Puthikorn Voravootivat | 5d98386 | 2013-10-29 17:50:19 -0700 | [diff] [blame] | 180 | """ |
| 181 | logging.info(str('_full_disk_write #%d' % self._loop_count)) |
Puthikorn Voravootivat | 5d98386 | 2013-10-29 17:50:19 -0700 | [diff] [blame] | 182 | |
Gwendal Grignou | 14bd4ba | 2014-06-04 16:38:35 -0700 | [diff] [blame] | 183 | # use the default requirement that write different pattern arround. |
| 184 | self._client_at.run_test('hardware_StorageFio', |
Gwendal Grignou | ae36712 | 2015-02-25 10:58:51 -0800 | [diff] [blame] | 185 | disable_sysinfo=True, |
Gwendal Grignou | 14bd4ba | 2014-06-04 16:38:35 -0700 | [diff] [blame] | 186 | tag='%s_%d' % ('soak', self._loop_count), |
| 187 | requirements=[('64k_stress', [])], |
| 188 | time_length=self._soak_time) |
| 189 | self._check_client_test_result(self._client) |
Puthikorn Voravootivat | 5d98386 | 2013-10-29 17:50:19 -0700 | [diff] [blame] | 190 | |
Gwendal Grignou | 14bd4ba | 2014-06-04 16:38:35 -0700 | [diff] [blame] | 191 | self._client_at.run_test('hardware_StorageFio', |
Gwendal Grignou | ae36712 | 2015-02-25 10:58:51 -0800 | [diff] [blame] | 192 | disable_sysinfo=True, |
Gwendal Grignou | 14bd4ba | 2014-06-04 16:38:35 -0700 | [diff] [blame] | 193 | tag='%s_%d' % ('surf', self._loop_count), |
| 194 | requirements=[('surfing', [])], |
| 195 | time_length=self._soak_time) |
| 196 | self._check_client_test_result(self._client) |
Puthikorn Voravootivat | 5d98386 | 2013-10-29 17:50:19 -0700 | [diff] [blame] | 197 | |
Gwendal Grignou | 14bd4ba | 2014-06-04 16:38:35 -0700 | [diff] [blame] | 198 | self._client_at.run_test('hardware_StorageFio', |
Gwendal Grignou | ae36712 | 2015-02-25 10:58:51 -0800 | [diff] [blame] | 199 | disable_sysinfo=True, |
Gwendal Grignou | 14bd4ba | 2014-06-04 16:38:35 -0700 | [diff] [blame] | 200 | tag='%s_%d' % ('integrity', self._loop_count), |
| 201 | wait=0, integrity=True) |
| 202 | self._check_client_test_result(self._client) |
Puthikorn Voravootivat | 5d98386 | 2013-10-29 17:50:19 -0700 | [diff] [blame] | 203 | |
Gwendal Grignou | 14bd4ba | 2014-06-04 16:38:35 -0700 | [diff] [blame] | 204 | self._client_at.run_test('hardware_StorageWearoutDetect', |
| 205 | tag='%s_%d' % ('wearout', self._loop_count), |
| 206 | wait=0, use_cached_result=False) |
| 207 | # No checkout for wearout, to test device pass their limits. |