docs: change listed type for log_window_value to str
[fio.git] / t / nvmept.py
CommitLineData
b03ed937
VF
1#!/usr/bin/env python3
2"""
3# nvmept.py
4#
5# Test fio's io_uring_cmd ioengine with NVMe pass-through commands.
6#
7# USAGE
8# see python3 nvmept.py --help
9#
10# EXAMPLES
11# python3 t/nvmept.py --dut /dev/ng0n1
12# python3 t/nvmept.py --dut /dev/ng1n1 -f ./fio
13#
14# REQUIREMENTS
15# Python 3.6
16#
17"""
18import os
19import sys
b03ed937 20import time
b03ed937 21import argparse
b03ed937 22from pathlib import Path
cebaf30e 23from fiotestlib import FioJobCmdTest, run_fio_tests
b03ed937 24
b03ed937 25
cebaf30e
VF
26class PassThruTest(FioJobCmdTest):
27 """
28 NVMe pass-through test class. Check to make sure output for selected data
29 direction(s) is non-zero and that zero data appears for other directions.
30 """
b03ed937 31
cebaf30e
VF
32 def setup(self, parameters):
33 """Setup a test."""
b03ed937
VF
34
35 fio_args = [
36 "--name=nvmept",
37 "--ioengine=io_uring_cmd",
38 "--cmd_type=nvme",
39 "--iodepth=8",
40 "--iodepth_batch=4",
41 "--iodepth_batch_complete=4",
cebaf30e
VF
42 f"--filename={self.fio_opts['filename']}",
43 f"--rw={self.fio_opts['rw']}",
b03ed937 44 f"--output={self.filenames['output']}",
cebaf30e 45 f"--output-format={self.fio_opts['output-format']}",
b03ed937
VF
46 ]
47 for opt in ['fixedbufs', 'nonvectored', 'force_async', 'registerfiles',
48 'sqthread_poll', 'sqthread_poll_cpu', 'hipri', 'nowait',
49 'time_based', 'runtime', 'verify', 'io_size']:
cebaf30e
VF
50 if opt in self.fio_opts:
51 option = f"--{opt}={self.fio_opts[opt]}"
b03ed937
VF
52 fio_args.append(option)
53
cebaf30e 54 super().setup(fio_args)
b03ed937
VF
55
56
cebaf30e 57 def check_result(self):
4883f8f6
VF
58 super().check_result()
59
cebaf30e
VF
60 if 'rw' not in self.fio_opts:
61 return
b03ed937 62
cebaf30e
VF
63 if not self.passed:
64 return
b03ed937
VF
65
66 job = self.json_data['jobs'][0]
b03ed937 67
cebaf30e
VF
68 if self.fio_opts['rw'] in ['read', 'randread']:
69 self.passed = self.check_all_ddirs(['read'], job)
70 elif self.fio_opts['rw'] in ['write', 'randwrite']:
71 if 'verify' not in self.fio_opts:
72 self.passed = self.check_all_ddirs(['write'], job)
b03ed937 73 else:
cebaf30e
VF
74 self.passed = self.check_all_ddirs(['read', 'write'], job)
75 elif self.fio_opts['rw'] in ['trim', 'randtrim']:
76 self.passed = self.check_all_ddirs(['trim'], job)
77 elif self.fio_opts['rw'] in ['readwrite', 'randrw']:
78 self.passed = self.check_all_ddirs(['read', 'write'], job)
79 elif self.fio_opts['rw'] in ['trimwrite', 'randtrimwrite']:
80 self.passed = self.check_all_ddirs(['trim', 'write'], job)
b03ed937 81 else:
cebaf30e
VF
82 print(f"Unhandled rw value {self.fio_opts['rw']}")
83 self.passed = False
b03ed937 84
8604be05
VF
85 if job['iodepth_level']['8'] < 95:
86 print("Did not achieve requested iodepth")
87 self.passed = False
88
b03ed937 89
cebaf30e
VF
90TEST_LIST = [
91 {
92 "test_id": 1,
93 "fio_opts": {
b03ed937
VF
94 "rw": 'read',
95 "timebased": 1,
96 "runtime": 3,
97 "output-format": "json",
cebaf30e
VF
98 },
99 "test_class": PassThruTest,
100 },
101 {
102 "test_id": 2,
103 "fio_opts": {
b03ed937
VF
104 "rw": 'randread',
105 "timebased": 1,
106 "runtime": 3,
107 "output-format": "json",
cebaf30e
VF
108 },
109 "test_class": PassThruTest,
110 },
111 {
112 "test_id": 3,
113 "fio_opts": {
b03ed937
VF
114 "rw": 'write',
115 "timebased": 1,
116 "runtime": 3,
117 "output-format": "json",
cebaf30e
VF
118 },
119 "test_class": PassThruTest,
120 },
121 {
122 "test_id": 4,
123 "fio_opts": {
b03ed937
VF
124 "rw": 'randwrite',
125 "timebased": 1,
126 "runtime": 3,
127 "output-format": "json",
cebaf30e
VF
128 },
129 "test_class": PassThruTest,
130 },
131 {
132 "test_id": 5,
133 "fio_opts": {
b03ed937
VF
134 "rw": 'trim',
135 "timebased": 1,
136 "runtime": 3,
137 "output-format": "json",
cebaf30e
VF
138 },
139 "test_class": PassThruTest,
140 },
141 {
142 "test_id": 6,
143 "fio_opts": {
b03ed937
VF
144 "rw": 'randtrim',
145 "timebased": 1,
146 "runtime": 3,
147 "output-format": "json",
cebaf30e
VF
148 },
149 "test_class": PassThruTest,
150 },
151 {
152 "test_id": 7,
153 "fio_opts": {
b03ed937
VF
154 "rw": 'write',
155 "io_size": 1024*1024,
156 "verify": "crc32c",
157 "output-format": "json",
cebaf30e
VF
158 },
159 "test_class": PassThruTest,
160 },
161 {
162 "test_id": 8,
163 "fio_opts": {
b03ed937
VF
164 "rw": 'randwrite',
165 "io_size": 1024*1024,
166 "verify": "crc32c",
167 "output-format": "json",
cebaf30e
VF
168 },
169 "test_class": PassThruTest,
170 },
171 {
172 "test_id": 9,
173 "fio_opts": {
b03ed937
VF
174 "rw": 'readwrite',
175 "timebased": 1,
176 "runtime": 3,
177 "output-format": "json",
cebaf30e
VF
178 },
179 "test_class": PassThruTest,
180 },
181 {
182 "test_id": 10,
183 "fio_opts": {
b03ed937
VF
184 "rw": 'randrw',
185 "timebased": 1,
186 "runtime": 3,
187 "output-format": "json",
cebaf30e
VF
188 },
189 "test_class": PassThruTest,
190 },
191 {
192 "test_id": 11,
193 "fio_opts": {
b03ed937
VF
194 "rw": 'trimwrite',
195 "timebased": 1,
196 "runtime": 3,
197 "output-format": "json",
cebaf30e
VF
198 },
199 "test_class": PassThruTest,
200 },
201 {
202 "test_id": 12,
203 "fio_opts": {
b03ed937
VF
204 "rw": 'randtrimwrite',
205 "timebased": 1,
206 "runtime": 3,
207 "output-format": "json",
cebaf30e
VF
208 },
209 "test_class": PassThruTest,
210 },
211 {
212 "test_id": 13,
213 "fio_opts": {
b03ed937
VF
214 "rw": 'randread',
215 "timebased": 1,
216 "runtime": 3,
217 "fixedbufs": 1,
218 "nonvectored": 1,
219 "force_async": 1,
220 "registerfiles": 1,
221 "sqthread_poll": 1,
222 "output-format": "json",
cebaf30e
VF
223 },
224 "test_class": PassThruTest,
225 },
226 {
227 "test_id": 14,
228 "fio_opts": {
b03ed937
VF
229 "rw": 'randwrite',
230 "timebased": 1,
231 "runtime": 3,
232 "fixedbufs": 1,
233 "nonvectored": 1,
234 "force_async": 1,
235 "registerfiles": 1,
236 "sqthread_poll": 1,
237 "output-format": "json",
cebaf30e
VF
238 },
239 "test_class": PassThruTest,
240 },
d47132c6
VF
241 {
242 # We can't enable fixedbufs because for trim-only
243 # workloads fio actually does not allocate any buffers
244 "test_id": 15,
245 "fio_opts": {
246 "rw": 'randtrim',
247 "timebased": 1,
248 "runtime": 3,
249 "fixedbufs": 0,
250 "nonvectored": 1,
251 "force_async": 1,
252 "registerfiles": 1,
253 "sqthread_poll": 1,
254 "output-format": "json",
255 },
256 "test_class": PassThruTest,
257 },
cebaf30e 258]
b03ed937 259
cebaf30e
VF
260def parse_args():
261 """Parse command-line arguments."""
b03ed937 262
cebaf30e
VF
263 parser = argparse.ArgumentParser()
264 parser.add_argument('-f', '--fio', help='path to file executable (e.g., ./fio)')
265 parser.add_argument('-a', '--artifact-root', help='artifact root directory')
266 parser.add_argument('-s', '--skip', nargs='+', type=int,
267 help='list of test(s) to skip')
268 parser.add_argument('-o', '--run-only', nargs='+', type=int,
269 help='list of test(s) to run, skipping all others')
270 parser.add_argument('--dut', help='target NVMe character device to test '
271 '(e.g., /dev/ng0n1). WARNING: THIS IS A DESTRUCTIVE TEST', required=True)
272 args = parser.parse_args()
273
274 return args
275
276
277def main():
278 """Run tests using fio's io_uring_cmd ioengine to send NVMe pass through commands."""
279
280 args = parse_args()
281
282 artifact_root = args.artifact_root if args.artifact_root else \
283 f"nvmept-test-{time.strftime('%Y%m%d-%H%M%S')}"
284 os.mkdir(artifact_root)
285 print(f"Artifact directory is {artifact_root}")
286
287 if args.fio:
288 fio_path = str(Path(args.fio).absolute())
289 else:
290 fio_path = 'fio'
291 print(f"fio path is {fio_path}")
b03ed937 292
cebaf30e
VF
293 for test in TEST_LIST:
294 test['fio_opts']['filename'] = args.dut
b03ed937 295
cebaf30e
VF
296 test_env = {
297 'fio_path': fio_path,
298 'fio_root': str(Path(__file__).absolute().parent.parent),
299 'artifact_root': artifact_root,
df50839f 300 'basename': 'nvmept',
cebaf30e 301 }
b03ed937 302
cebaf30e 303 _, failed, _ = run_fio_tests(TEST_LIST, test_env, args)
b03ed937
VF
304 sys.exit(failed)
305
306
307if __name__ == '__main__':
308 main()