t/nvmept_trim: increase transfer size for some tests
[fio.git] / t / strided.py
CommitLineData
8c00c383 1#!/usr/bin/env python3
5a36d0e4
VF
2
3"""
6d5af490
VF
4# strided.py
5#
6# Test zonemode=strided. This uses the null ioengine when no file is
7# specified. If a file is specified, use it for randdom read testing.
8# Some of the zoneranges in the tests are 16MiB. So when using a file
03317fbb 9# a minimum size of 64MiB is recommended.
6d5af490
VF
10#
11# USAGE
12# python strided.py fio-executable [-f file/device]
13#
14# EXAMPLES
15# python t/strided.py ./fio
16# python t/strided.py ./fio -f /dev/sda
03317fbb 17# dd if=/dev/zero of=temp bs=1M count=64
6d5af490
VF
18# python t/strided.py ./fio -f temp
19#
6d5af490
VF
20# ===TEST MATRIX===
21#
fa9fd914 22# --zonemode=strided, zoneskip unset
6d5af490
VF
23# w/ randommap and LFSR
24# zonesize=zonerange all blocks in zonerange touched
25# zonesize>zonerange all blocks touched and roll-over back into zone
26# zonesize<zonerange all blocks inside zone
27#
28# w/o randommap all blocks inside zone
5a36d0e4 29"""
6d5af490 30
6d5af490
VF
31import os
32import sys
5a36d0e4 33import time
6d5af490 34import argparse
5a36d0e4
VF
35from pathlib import Path
36from fiotestlib import FioJobCmdTest, run_fio_tests
6d5af490
VF
37
38
5a36d0e4
VF
39class StridedTest(FioJobCmdTest):
40 """Test zonemode=strided."""
6d5af490 41
5a36d0e4
VF
42 def setup(self, parameters):
43 fio_args = [
44 "--name=strided",
45 "--zonemode=strided",
46 "--log_offset=1",
47 "--randrepeat=0",
48 "--rw=randread",
49 f"--write_iops_log={self.filenames['iopslog']}",
50 f"--output={self.filenames['output']}",
51 f"--zonerange={self.fio_opts['zonerange']}",
52 f"--zonesize={self.fio_opts['zonesize']}",
53 f"--bs={self.fio_opts['bs']}",
54 ]
6d5af490 55
5a36d0e4
VF
56 for opt in ['norandommap', 'random_generator', 'offset']:
57 if opt in self.fio_opts:
58 option = f"--{opt}={self.fio_opts[opt]}"
59 fio_args.append(option)
6d5af490 60
5a36d0e4
VF
61 if 'filename' in self.fio_opts:
62 for opt in ['filename', 'filesize']:
63 option = f"--{opt}={self.fio_opts[opt]}"
64 fio_args.append(option)
65 else:
66 fio_args.append('--ioengine=null')
67 for opt in ['size', 'io_size', 'filesize']:
68 option = f"--{opt}={self.fio_opts[opt]}"
69 fio_args.append(option)
70
71 super().setup(fio_args)
72
73 def check_result(self):
f4c55efe
VF
74 super().check_result()
75 if not self.passed:
76 return
77
5a36d0e4
VF
78 zonestart = 0 if 'offset' not in self.fio_opts else self.fio_opts['offset']
79 iospersize = self.fio_opts['zonesize'] / self.fio_opts['bs']
80 iosperrange = self.fio_opts['zonerange'] / self.fio_opts['bs']
81 iosperzone = 0
82 lines = self.iops_log_lines.split('\n')
83 zoneset = set()
84
85 for line in lines:
86 if len(line) == 0:
6d5af490
VF
87 continue
88
5a36d0e4
VF
89 if iosperzone == iospersize:
90 # time to move to a new zone
91 iosperzone = 0
92 zoneset = set()
93 zonestart += self.fio_opts['zonerange']
94 if zonestart >= self.fio_opts['filesize']:
95 zonestart = 0 if 'offset' not in self.fio_opts else self.fio_opts['offset']
96
97 iosperzone = iosperzone + 1
98 tokens = line.split(',')
99 offset = int(tokens[4])
100 if offset < zonestart or offset >= zonestart + self.fio_opts['zonerange']:
101 print(f"Offset {offset} outside of zone starting at {zonestart}")
06c40418 102 return
6d5af490 103
5a36d0e4
VF
104 # skip next section if norandommap is enabled with no
105 # random_generator or with a random_generator != lfsr
106 if 'norandommap' in self.fio_opts:
107 if 'random_generator' in self.fio_opts:
108 if self.fio_opts['random_generator'] != 'lfsr':
109 continue
110 else:
111 continue
6d5af490 112
5a36d0e4
VF
113 # we either have a random map enabled or we
114 # are using an LFSR
115 # so all blocks should be unique and we should have
116 # covered the entire zone when iosperzone % iosperrange == 0
117 block = (offset - zonestart) / self.fio_opts['bs']
118 if block in zoneset:
119 print(f"Offset {offset} in zone already touched")
06c40418 120 return
5a36d0e4
VF
121
122 zoneset.add(block)
123 if iosperzone % iosperrange == 0:
124 if len(zoneset) != iosperrange:
125 print(f"Expected {iosperrange} blocks in zone but only saw {len(zoneset)}")
06c40418 126 return
5a36d0e4
VF
127 zoneset = set()
128
5a36d0e4
VF
129
130TEST_LIST = [ # randommap enabled
131 {
132 "test_id": 1,
133 "fio_opts": {
134 "zonerange": 4096,
135 "zonesize": 4096,
136 "bs": 4096,
137 "offset": 8*4096,
138 "size": 16*4096,
139 "io_size": 16*4096,
140 },
141 "test_class": StridedTest,
142 },
143 {
144 "test_id": 2,
145 "fio_opts": {
146 "zonerange": 4096,
147 "zonesize": 4096,
148 "bs": 4096,
149 "size": 16*4096,
150 "io_size": 16*4096,
151 },
152 "test_class": StridedTest,
153 },
154 {
155 "test_id": 3,
156 "fio_opts": {
157 "zonerange": 16*1024*1024,
158 "zonesize": 16*1024*1024,
159 "bs": 4096,
160 "size": 256*1024*1024,
161 "io_size": 256*1024*204,
162 },
163 "test_class": StridedTest,
164 },
165 {
166 "test_id": 4,
167 "fio_opts": {
168 "zonerange": 4096,
169 "zonesize": 4*4096,
170 "bs": 4096,
171 "size": 16*4096,
172 "io_size": 16*4096,
173 },
174 "test_class": StridedTest,
175 },
176 {
177 "test_id": 5,
178 "fio_opts": {
179 "zonerange": 16*1024*1024,
180 "zonesize": 32*1024*1024,
181 "bs": 4096,
182 "size": 256*1024*1024,
183 "io_size": 256*1024*204,
184 },
185 "test_class": StridedTest,
186 },
187 {
188 "test_id": 6,
189 "fio_opts": {
190 "zonerange": 8192,
191 "zonesize": 4096,
192 "bs": 4096,
193 "size": 16*4096,
194 "io_size": 16*4096,
195 },
196 "test_class": StridedTest,
197 },
198 {
199 "test_id": 7,
200 "fio_opts": {
201 "zonerange": 16*1024*1024,
202 "zonesize": 8*1024*1024,
203 "bs": 4096,
204 "size": 256*1024*1024,
205 "io_size": 256*1024*204,
206 },
207 "test_class": StridedTest,
208 },
209 # lfsr
210 {
211 "test_id": 8,
212 "fio_opts": {
213 "random_generator": "lfsr",
214 "zonerange": 4096*1024,
215 "zonesize": 4096*1024,
216 "bs": 4096,
217 "offset": 8*4096*1024,
218 "size": 16*4096*1024,
219 "io_size": 16*4096*1024,
220 },
221 "test_class": StridedTest,
222 },
223 {
224 "test_id": 9,
225 "fio_opts": {
226 "random_generator": "lfsr",
227 "zonerange": 4096*1024,
228 "zonesize": 4096*1024,
229 "bs": 4096,
230 "size": 16*4096*1024,
231 "io_size": 16*4096*1024,
232 },
233 "test_class": StridedTest,
234 },
235 {
236 "test_id": 10,
237 "fio_opts": {
238 "random_generator": "lfsr",
239 "zonerange": 16*1024*1024,
240 "zonesize": 16*1024*1024,
241 "bs": 4096,
242 "size": 256*1024*1024,
243 "io_size": 256*1024*204,
244 },
245 "test_class": StridedTest,
246 },
247 {
248 "test_id": 11,
249 "fio_opts": {
250 "random_generator": "lfsr",
251 "zonerange": 4096*1024,
252 "zonesize": 4*4096*1024,
253 "bs": 4096,
254 "size": 16*4096*1024,
255 "io_size": 16*4096*1024,
256 },
257 "test_class": StridedTest,
258 },
259 {
260 "test_id": 12,
261 "fio_opts": {
262 "random_generator": "lfsr",
263 "zonerange": 16*1024*1024,
264 "zonesize": 32*1024*1024,
265 "bs": 4096,
266 "size": 256*1024*1024,
267 "io_size": 256*1024*204,
268 },
269 "test_class": StridedTest,
270 },
271 {
272 "test_id": 13,
273 "fio_opts": {
274 "random_generator": "lfsr",
275 "zonerange": 8192*1024,
276 "zonesize": 4096*1024,
277 "bs": 4096,
278 "size": 16*4096*1024,
279 "io_size": 16*4096*1024,
280 },
281 "test_class": StridedTest,
282 },
283 {
284 "test_id": 14,
285 "fio_opts": {
286 "random_generator": "lfsr",
287 "zonerange": 16*1024*1024,
288 "zonesize": 8*1024*1024,
289 "bs": 4096,
290 "size": 256*1024*1024,
291 "io_size": 256*1024*204,
292 },
293 "test_class": StridedTest,
294 },
295 # norandommap
296 {
297 "test_id": 15,
298 "fio_opts": {
299 "norandommap": 1,
300 "zonerange": 4096,
301 "zonesize": 4096,
302 "bs": 4096,
303 "offset": 8*4096,
304 "size": 16*4096,
305 "io_size": 16*4096,
306 },
307 "test_class": StridedTest,
308 },
309 {
310 "test_id": 16,
311 "fio_opts": {
312 "norandommap": 1,
313 "zonerange": 4096,
314 "zonesize": 4096,
315 "bs": 4096,
316 "size": 16*4096,
317 "io_size": 16*4096,
318 },
319 "test_class": StridedTest,
320 },
321 {
322 "test_id": 17,
323 "fio_opts": {
324 "norandommap": 1,
325 "zonerange": 16*1024*1024,
326 "zonesize": 16*1024*1024,
327 "bs": 4096,
328 "size": 256*1024*1024,
329 "io_size": 256*1024*204,
330 },
331 "test_class": StridedTest,
332 },
333 {
334 "test_id": 18,
335 "fio_opts": {
336 "norandommap": 1,
337 "zonerange": 4096,
338 "zonesize": 8192,
339 "bs": 4096,
340 "size": 16*4096,
341 "io_size": 16*4096,
342 },
343 "test_class": StridedTest,
344 },
345 {
346 "test_id": 19,
347 "fio_opts": {
348 "norandommap": 1,
349 "zonerange": 16*1024*1024,
350 "zonesize": 32*1024*1024,
351 "bs": 4096,
352 "size": 256*1024*1024,
353 "io_size": 256*1024*204,
354 },
355 "test_class": StridedTest,
356 },
357 {
358 "test_id": 20,
359 "fio_opts": {
360 "norandommap": 1,
361 "zonerange": 8192,
362 "zonesize": 4096,
363 "bs": 4096,
364 "size": 16*4096,
365 "io_size": 16*4096,
366 },
367 "test_class": StridedTest,
368 },
369 {
370 "test_id": 21,
371 "fio_opts": {
372 "norandommap": 1,
373 "zonerange": 16*1024*1024,
374 "zonesize": 8*1024*1024,
375 "bs": 4096,
376 "size": 256*1024*1024,
377 "io_size": 256*1024*1024,
378 },
379 "test_class": StridedTest,
380 },
381]
382
383
384def parse_args():
385 """Parse command-line arguments."""
386
387 parser = argparse.ArgumentParser()
388 parser.add_argument('-f', '--fio', help='path to file executable (e.g., ./fio)')
389 parser.add_argument('-a', '--artifact-root', help='artifact root directory')
390 parser.add_argument('-s', '--skip', nargs='+', type=int,
391 help='list of test(s) to skip')
392 parser.add_argument('-o', '--run-only', nargs='+', type=int,
393 help='list of test(s) to run, skipping all others')
394 parser.add_argument('--dut',
395 help='target file/device to test.')
396 args = parser.parse_args()
397
398 return args
399
400
401def main():
402 """Run zonemode=strided tests."""
6d5af490 403
6d5af490
VF
404 args = parse_args()
405
5a36d0e4
VF
406 artifact_root = args.artifact_root if args.artifact_root else \
407 f"strided-test-{time.strftime('%Y%m%d-%H%M%S')}"
408 os.mkdir(artifact_root)
409 print(f"Artifact directory is {artifact_root}")
410
411 if args.fio:
412 fio_path = str(Path(args.fio).absolute())
413 else:
414 fio_path = 'fio'
415 print(f"fio path is {fio_path}")
416
417 if args.dut:
418 statinfo = os.stat(args.dut)
6d5af490
VF
419 filesize = statinfo.st_size
420 if filesize == 0:
5a36d0e4 421 f = os.open(args.dut, os.O_RDONLY)
6d5af490
VF
422 filesize = os.lseek(f, 0, os.SEEK_END)
423 os.close(f)
424
5a36d0e4
VF
425 for test in TEST_LIST:
426 if args.dut:
427 test['fio_opts']['filename'] = os.path.abspath(args.dut)
428 test['fio_opts']['filesize'] = filesize
6d5af490 429 else:
5a36d0e4 430 test['fio_opts']['filesize'] = test['fio_opts']['size']
6d5af490 431
5a36d0e4
VF
432 test_env = {
433 'fio_path': fio_path,
434 'fio_root': str(Path(__file__).absolute().parent.parent),
435 'artifact_root': artifact_root,
436 'basename': 'strided',
437 }
6d5af490 438
5a36d0e4 439 _, failed, _ = run_fio_tests(TEST_LIST, test_env, args)
6d5af490 440 sys.exit(failed)
5a36d0e4
VF
441
442
443if __name__ == '__main__':
444 main()