blob: f202e162f30e8f3b38c24aedb5fa8f11c820f340 [file] [log] [blame]
Puthikorn Voravootivat8c1f4342013-10-24 14:18:41 -07001# 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 Grignou14bd4ba2014-06-04 16:38:35 -07005import logging, sys, time
Puthikorn Voravootivat8c1f4342013-10-24 14:18:41 -07006from autotest_lib.client.common_lib import error
7from autotest_lib.server import autotest
8from autotest_lib.server import hosts
Puthikorn Voravootivat7334d692013-10-29 16:55:37 -07009from autotest_lib.server import test
Puthikorn Voravootivat8c1f4342013-10-24 14:18:41 -070010
11class hardware_StorageStress(test.test):
12 """
13 Integrity stress test for storage device
14 """
15 version = 1
16
Gwendal Grignou14bd4ba2014-06-04 16:38:35 -070017 _HOURS_IN_SEC = 3600
Puthikorn Voravootivat8c1f4342013-10-24 14:18:41 -070018 # Define default value for the test case
19 _TEST_GAP = 60 # 1 min
Gwendal Grignou14bd4ba2014-06-04 16:38:35 -070020 _TEST_DURATION = 12 * _HOURS_IN_SEC
21 _SUSPEND_DURATION = _HOURS_IN_SEC
Puthikorn Voravootivat8c1f4342013-10-24 14:18:41 -070022 _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 Voravootivat5d983862013-10-29 17:50:19 -070027 power_command='reboot', storage_test_command='integrity',
Gwendal Grignou7a61d2f2014-05-23 11:05:51 -070028 suspend_duration=_SUSPEND_DURATION, storage_test_argument=''):
Puthikorn Voravootivat8c1f4342013-10-24 14:18:41 -070029 """
Puthikorn Voravootivat59617882013-10-29 17:31:37 -070030 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 Voravootivat8c1f4342013-10-24 14:18:41 -070034
Puthikorn Voravootivat59617882013-10-29 17:31:37 -070035 @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 Voravootivat5d983862013-10-29 17:50:19 -070040 @param storage_test_command: FIO command to run
Puthikorn Voravootivat59617882013-10-29 17:31:37 -070041 - integrity: Check data integrity
Puthikorn Voravootivat5d983862013-10-29 17:50:19 -070042 - full_write: Check performance consistency
43 for full disk write. Use argument
44 to determine which disk to write
Gwendal Grignou7a61d2f2014-05-23 11:05:51 -070045 @param suspend_duration: if power_command is suspend, how long the DUT
46 is suspended.
Puthikorn Voravootivat8c1f4342013-10-24 14:18:41 -070047 """
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 Grignou7a61d2f2014-05-23 11:05:51 -070056 self._suspend_duration = suspend_duration
Puthikorn Voravootivat8c1f4342013-10-24 14:18:41 -070057
Puthikorn Voravootivat59617882013-10-29 17:31:37 -070058 # 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 Voravootivat8c1f4342013-10-24 14:18:41 -070065 else:
Puthikorn Voravootivat59617882013-10-29 17:31:37 -070066 raise error.TestFail(
67 'Test failed with error: Invalid power command')
Puthikorn Voravootivat8c1f4342013-10-24 14:18:41 -070068
Gwendal Grignou96652f02015-11-04 10:24:11 -080069 # 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 Voravootivat59617882013-10-29 17:31:37 -070072 # parse test command
Puthikorn Voravootivat5d983862013-10-29 17:50:19 -070073 if storage_test_command == 'integrity':
Puthikorn Voravootivat59617882013-10-29 17:31:37 -070074 setup_func = self._write_data
75 loop_func = self._verify_data
Puthikorn Voravootivat5d983862013-10-29 17:50:19 -070076 elif storage_test_command == 'full_write':
77 setup_func = self._do_nothing
Gwendal Grignou14bd4ba2014-06-04 16:38:35 -070078 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 Voravootivat59617882013-10-29 17:31:37 -070082 else:
83 raise error.TestFail('Test failed with error: Invalid test command')
84
Puthikorn Voravootivat8c1f4342013-10-24 14:18:41 -070085 # init statistic variable
Gwendal Grignou14bd4ba2014-06-04 16:38:35 -070086 min_time_per_loop = sys.maxsize
Puthikorn Voravootivat8c1f4342013-10-24 14:18:41 -070087 max_time_per_loop = 0
88 all_loop_time = 0
89 avr_time_per_loop = 0
Puthikorn Voravootivat59617882013-10-29 17:31:37 -070090 self._loop_count = 0
Gwendal Grignou72e54122014-06-22 10:58:21 -070091 setup_func()
Puthikorn Voravootivat8c1f4342013-10-24 14:18:41 -070092
Gwendal Grignou7a61d2f2014-05-23 11:05:51 -070093 start_time = time.time()
94
Puthikorn Voravootivat8c1f4342013-10-24 14:18:41 -070095 while time.time() - start_time < duration:
96 # sleep
97 time.sleep(gap)
98
Puthikorn Voravootivat59617882013-10-29 17:31:37 -070099 self._loop_count += 1
100
Puthikorn Voravootivat8c1f4342013-10-24 14:18:41 -0700101 # do power command & verify data & calculate time
102 loop_start_time = time.time()
Puthikorn Voravootivat59617882013-10-29 17:31:37 -0700103 power_func()
104 loop_func()
Puthikorn Voravootivat8c1f4342013-10-24 14:18:41 -0700105 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 Voravootivat59617882013-10-29 17:31:37 -0700112 if self._loop_count > 0:
113 avr_time_per_loop = all_loop_time / self._loop_count
Puthikorn Voravootivat8c1f4342013-10-24 14:18:41 -0700114
Puthikorn Voravootivat59617882013-10-29 17:31:37 -0700115 logging.info(str('check data count: %d' % self._loop_count))
Puthikorn Voravootivat8c1f4342013-10-24 14:18:41 -0700116
117 # report result
Puthikorn Voravootivat59617882013-10-29 17:31:37 -0700118 self.write_perf_keyval({'loop_count':self._loop_count})
Puthikorn Voravootivat8c1f4342013-10-24 14:18:41 -0700119 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 Voravootivat59617882013-10-29 17:31:37 -0700123 def _do_nothing(self):
124 pass
125
Puthikorn Voravootivat8c1f4342013-10-24 14:18:41 -0700126 def _do_reboot(self):
127 """
128 Reboot host machine
129 """
Gwendal Grignou7a61d2f2014-05-23 11:05:51 -0700130 self._client.reboot()
Puthikorn Voravootivat8c1f4342013-10-24 14:18:41 -0700131
132 def _do_suspend(self):
133 """
134 Suspend host machine
135 """
Gwendal Grignou7a61d2f2014-05-23 11:05:51 -0700136 self._client.suspend(suspend_time=self._suspend_duration)
Puthikorn Voravootivat8c1f4342013-10-24 14:18:41 -0700137
Gwendal Grignou14bd4ba2014-06-04 16:38:35 -0700138 @classmethod
139 def _check_client_test_result(cls, client):
Puthikorn Voravootivat8c1f4342013-10-24 14:18:41 -0700140 """
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 Grignou14bd4ba2014-06-04 16:38:35 -0700145 @ raise an error if test fails.
Puthikorn Voravootivat8c1f4342013-10-24 14:18:41 -0700146 """
Puthikorn Voravootivat7334d692013-10-29 16:55:37 -0700147 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 Voravootivat8c1f4342013-10-24 14:18:41 -0700150 logging.info(status)
Gwendal Grignou14bd4ba2014-06-04 16:38:35 -0700151 if status[:8] != 'END GOOD':
152 raise error.TestFail('client in StorageStress failed.')
153
Puthikorn Voravootivat8c1f4342013-10-24 14:18:41 -0700154
Puthikorn Voravootivat8c1f4342013-10-24 14:18:41 -0700155 def _write_data(self):
156 """
157 Write test data to host using hardware_StorageFio
158 """
159 logging.info('_write_data')
Gwendal Grignouae367122015-02-25 10:58:51 -0800160 self._client_at.run_test('hardware_StorageFio', disable_sysinfo=True,
161 wait=0, tag='%s_%d' % ('write_data', self._loop_count),
Gwendal Grignou14bd4ba2014-06-04 16:38:35 -0700162 requirements=[(self._FIO_REQUIREMENT_FILE, self._FIO_WRITE_FLAGS)])
163 self._check_client_test_result(self._client)
Puthikorn Voravootivat8c1f4342013-10-24 14:18:41 -0700164
165 def _verify_data(self):
166 """
Gwendal Grignou14bd4ba2014-06-04 16:38:35 -0700167 Verify test data using hardware_StorageFio
Puthikorn Voravootivat8c1f4342013-10-24 14:18:41 -0700168 """
Puthikorn Voravootivat59617882013-10-29 17:31:37 -0700169 logging.info(str('_verify_data #%d' % self._loop_count))
Gwendal Grignouae367122015-02-25 10:58:51 -0800170 self._client_at.run_test('hardware_StorageFio', disable_sysinfo=True,
171 wait=0, tag='%s_%d' % ('verify_data', self._loop_count),
Gwendal Grignou14bd4ba2014-06-04 16:38:35 -0700172 requirements=[(self._FIO_REQUIREMENT_FILE, self._FIO_VERIFY_FLAGS)])
173 self._check_client_test_result(self._client)
Puthikorn Voravootivat5d983862013-10-29 17:50:19 -0700174
Gwendal Grignou14bd4ba2014-06-04 16:38:35 -0700175 def _full_disk_write(self):
Puthikorn Voravootivat5d983862013-10-29 17:50:19 -0700176 """
177 Do the root device full area write and report performance
Gwendal Grignou14bd4ba2014-06-04 16:38:35 -0700178 Write random pattern for few hours, then do a write and a verify,
179 noting the latency.
Puthikorn Voravootivat5d983862013-10-29 17:50:19 -0700180 """
181 logging.info(str('_full_disk_write #%d' % self._loop_count))
Puthikorn Voravootivat5d983862013-10-29 17:50:19 -0700182
Gwendal Grignou14bd4ba2014-06-04 16:38:35 -0700183 # use the default requirement that write different pattern arround.
184 self._client_at.run_test('hardware_StorageFio',
Gwendal Grignouae367122015-02-25 10:58:51 -0800185 disable_sysinfo=True,
Gwendal Grignou14bd4ba2014-06-04 16:38:35 -0700186 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 Voravootivat5d983862013-10-29 17:50:19 -0700190
Gwendal Grignou14bd4ba2014-06-04 16:38:35 -0700191 self._client_at.run_test('hardware_StorageFio',
Gwendal Grignouae367122015-02-25 10:58:51 -0800192 disable_sysinfo=True,
Gwendal Grignou14bd4ba2014-06-04 16:38:35 -0700193 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 Voravootivat5d983862013-10-29 17:50:19 -0700197
Gwendal Grignou14bd4ba2014-06-04 16:38:35 -0700198 self._client_at.run_test('hardware_StorageFio',
Gwendal Grignouae367122015-02-25 10:58:51 -0800199 disable_sysinfo=True,
Gwendal Grignou14bd4ba2014-06-04 16:38:35 -0700200 tag='%s_%d' % ('integrity', self._loop_count),
201 wait=0, integrity=True)
202 self._check_client_test_result(self._client)
Puthikorn Voravootivat5d983862013-10-29 17:50:19 -0700203
Gwendal Grignou14bd4ba2014-06-04 16:38:35 -0700204 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.