engines:io_uring: enable support for separate metadata buffer
[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
VF
57 def check_result(self):
58 if 'rw' not in self.fio_opts:
59 return
b03ed937 60
cebaf30e
VF
61 if not self.passed:
62 return
b03ed937
VF
63
64 job = self.json_data['jobs'][0]
b03ed937 65
cebaf30e
VF
66 if self.fio_opts['rw'] in ['read', 'randread']:
67 self.passed = self.check_all_ddirs(['read'], job)
68 elif self.fio_opts['rw'] in ['write', 'randwrite']:
69 if 'verify' not in self.fio_opts:
70 self.passed = self.check_all_ddirs(['write'], job)
b03ed937 71 else:
cebaf30e
VF
72 self.passed = self.check_all_ddirs(['read', 'write'], job)
73 elif self.fio_opts['rw'] in ['trim', 'randtrim']:
74 self.passed = self.check_all_ddirs(['trim'], job)
75 elif self.fio_opts['rw'] in ['readwrite', 'randrw']:
76 self.passed = self.check_all_ddirs(['read', 'write'], job)
77 elif self.fio_opts['rw'] in ['trimwrite', 'randtrimwrite']:
78 self.passed = self.check_all_ddirs(['trim', 'write'], job)
b03ed937 79 else:
cebaf30e
VF
80 print(f"Unhandled rw value {self.fio_opts['rw']}")
81 self.passed = False
b03ed937 82
8604be05
VF
83 if job['iodepth_level']['8'] < 95:
84 print("Did not achieve requested iodepth")
85 self.passed = False
86
b03ed937 87
cebaf30e
VF
88TEST_LIST = [
89 {
90 "test_id": 1,
91 "fio_opts": {
b03ed937
VF
92 "rw": 'read',
93 "timebased": 1,
94 "runtime": 3,
95 "output-format": "json",
cebaf30e
VF
96 },
97 "test_class": PassThruTest,
98 },
99 {
100 "test_id": 2,
101 "fio_opts": {
b03ed937
VF
102 "rw": 'randread',
103 "timebased": 1,
104 "runtime": 3,
105 "output-format": "json",
cebaf30e
VF
106 },
107 "test_class": PassThruTest,
108 },
109 {
110 "test_id": 3,
111 "fio_opts": {
b03ed937
VF
112 "rw": 'write',
113 "timebased": 1,
114 "runtime": 3,
115 "output-format": "json",
cebaf30e
VF
116 },
117 "test_class": PassThruTest,
118 },
119 {
120 "test_id": 4,
121 "fio_opts": {
b03ed937
VF
122 "rw": 'randwrite',
123 "timebased": 1,
124 "runtime": 3,
125 "output-format": "json",
cebaf30e
VF
126 },
127 "test_class": PassThruTest,
128 },
129 {
130 "test_id": 5,
131 "fio_opts": {
b03ed937
VF
132 "rw": 'trim',
133 "timebased": 1,
134 "runtime": 3,
135 "output-format": "json",
cebaf30e
VF
136 },
137 "test_class": PassThruTest,
138 },
139 {
140 "test_id": 6,
141 "fio_opts": {
b03ed937
VF
142 "rw": 'randtrim',
143 "timebased": 1,
144 "runtime": 3,
145 "output-format": "json",
cebaf30e
VF
146 },
147 "test_class": PassThruTest,
148 },
149 {
150 "test_id": 7,
151 "fio_opts": {
b03ed937
VF
152 "rw": 'write',
153 "io_size": 1024*1024,
154 "verify": "crc32c",
155 "output-format": "json",
cebaf30e
VF
156 },
157 "test_class": PassThruTest,
158 },
159 {
160 "test_id": 8,
161 "fio_opts": {
b03ed937
VF
162 "rw": 'randwrite',
163 "io_size": 1024*1024,
164 "verify": "crc32c",
165 "output-format": "json",
cebaf30e
VF
166 },
167 "test_class": PassThruTest,
168 },
169 {
170 "test_id": 9,
171 "fio_opts": {
b03ed937
VF
172 "rw": 'readwrite',
173 "timebased": 1,
174 "runtime": 3,
175 "output-format": "json",
cebaf30e
VF
176 },
177 "test_class": PassThruTest,
178 },
179 {
180 "test_id": 10,
181 "fio_opts": {
b03ed937
VF
182 "rw": 'randrw',
183 "timebased": 1,
184 "runtime": 3,
185 "output-format": "json",
cebaf30e
VF
186 },
187 "test_class": PassThruTest,
188 },
189 {
190 "test_id": 11,
191 "fio_opts": {
b03ed937
VF
192 "rw": 'trimwrite',
193 "timebased": 1,
194 "runtime": 3,
195 "output-format": "json",
cebaf30e
VF
196 },
197 "test_class": PassThruTest,
198 },
199 {
200 "test_id": 12,
201 "fio_opts": {
b03ed937
VF
202 "rw": 'randtrimwrite',
203 "timebased": 1,
204 "runtime": 3,
205 "output-format": "json",
cebaf30e
VF
206 },
207 "test_class": PassThruTest,
208 },
209 {
210 "test_id": 13,
211 "fio_opts": {
b03ed937
VF
212 "rw": 'randread',
213 "timebased": 1,
214 "runtime": 3,
215 "fixedbufs": 1,
216 "nonvectored": 1,
217 "force_async": 1,
218 "registerfiles": 1,
219 "sqthread_poll": 1,
220 "output-format": "json",
cebaf30e
VF
221 },
222 "test_class": PassThruTest,
223 },
224 {
225 "test_id": 14,
226 "fio_opts": {
b03ed937
VF
227 "rw": 'randwrite',
228 "timebased": 1,
229 "runtime": 3,
230 "fixedbufs": 1,
231 "nonvectored": 1,
232 "force_async": 1,
233 "registerfiles": 1,
234 "sqthread_poll": 1,
235 "output-format": "json",
cebaf30e
VF
236 },
237 "test_class": PassThruTest,
238 },
d47132c6
VF
239 {
240 # We can't enable fixedbufs because for trim-only
241 # workloads fio actually does not allocate any buffers
242 "test_id": 15,
243 "fio_opts": {
244 "rw": 'randtrim',
245 "timebased": 1,
246 "runtime": 3,
247 "fixedbufs": 0,
248 "nonvectored": 1,
249 "force_async": 1,
250 "registerfiles": 1,
251 "sqthread_poll": 1,
252 "output-format": "json",
253 },
254 "test_class": PassThruTest,
255 },
cebaf30e 256]
b03ed937 257
cebaf30e
VF
258def parse_args():
259 """Parse command-line arguments."""
b03ed937 260
cebaf30e
VF
261 parser = argparse.ArgumentParser()
262 parser.add_argument('-f', '--fio', help='path to file executable (e.g., ./fio)')
263 parser.add_argument('-a', '--artifact-root', help='artifact root directory')
264 parser.add_argument('-s', '--skip', nargs='+', type=int,
265 help='list of test(s) to skip')
266 parser.add_argument('-o', '--run-only', nargs='+', type=int,
267 help='list of test(s) to run, skipping all others')
268 parser.add_argument('--dut', help='target NVMe character device to test '
269 '(e.g., /dev/ng0n1). WARNING: THIS IS A DESTRUCTIVE TEST', required=True)
270 args = parser.parse_args()
271
272 return args
273
274
275def main():
276 """Run tests using fio's io_uring_cmd ioengine to send NVMe pass through commands."""
277
278 args = parse_args()
279
280 artifact_root = args.artifact_root if args.artifact_root else \
281 f"nvmept-test-{time.strftime('%Y%m%d-%H%M%S')}"
282 os.mkdir(artifact_root)
283 print(f"Artifact directory is {artifact_root}")
284
285 if args.fio:
286 fio_path = str(Path(args.fio).absolute())
287 else:
288 fio_path = 'fio'
289 print(f"fio path is {fio_path}")
b03ed937 290
cebaf30e
VF
291 for test in TEST_LIST:
292 test['fio_opts']['filename'] = args.dut
b03ed937 293
cebaf30e
VF
294 test_env = {
295 'fio_path': fio_path,
296 'fio_root': str(Path(__file__).absolute().parent.parent),
297 'artifact_root': artifact_root,
df50839f 298 'basename': 'nvmept',
cebaf30e 299 }
b03ed937 300
cebaf30e 301 _, failed, _ = run_fio_tests(TEST_LIST, test_env, args)
b03ed937
VF
302 sys.exit(failed)
303
304
305if __name__ == '__main__':
306 main()