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
9 # a minimum size of 64MiB is recommended.
12 # python strided.py fio-executable [-f file/device]
15 # python t/strided.py ./fio
16 # python t/strided.py ./fio -f /dev/sda
17 # dd if=/dev/zero of=temp bs=1M count=64
18 # python t/strided.py ./fio -f temp
22 # --zonemode=strided, zoneskip unset
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
28 # w/o randommap all blocks inside zone
35 from pathlib import Path
36 from fiotestlib import FioJobCmdTest, run_fio_tests
39 class StridedTest(FioJobCmdTest):
40 """Test zonemode=strided."""
42 def setup(self, parameters):
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']}",
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)
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)
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)
71 super().setup(fio_args)
73 def check_result(self):
74 zonestart = 0 if 'offset' not in self.fio_opts else self.fio_opts['offset']
75 iospersize = self.fio_opts['zonesize'] / self.fio_opts['bs']
76 iosperrange = self.fio_opts['zonerange'] / self.fio_opts['bs']
78 lines = self.iops_log_lines.split('\n')
85 if iosperzone == iospersize:
86 # time to move to a new zone
89 zonestart += self.fio_opts['zonerange']
90 if zonestart >= self.fio_opts['filesize']:
91 zonestart = 0 if 'offset' not in self.fio_opts else self.fio_opts['offset']
93 iosperzone = iosperzone + 1
94 tokens = line.split(',')
95 offset = int(tokens[4])
96 if offset < zonestart or offset >= zonestart + self.fio_opts['zonerange']:
97 print(f"Offset {offset} outside of zone starting at {zonestart}")
100 # skip next section if norandommap is enabled with no
101 # random_generator or with a random_generator != lfsr
102 if 'norandommap' in self.fio_opts:
103 if 'random_generator' in self.fio_opts:
104 if self.fio_opts['random_generator'] != 'lfsr':
109 # we either have a random map enabled or we
111 # so all blocks should be unique and we should have
112 # covered the entire zone when iosperzone % iosperrange == 0
113 block = (offset - zonestart) / self.fio_opts['bs']
115 print(f"Offset {offset} in zone already touched")
119 if iosperzone % iosperrange == 0:
120 if len(zoneset) != iosperrange:
121 print(f"Expected {iosperrange} blocks in zone but only saw {len(zoneset)}")
128 TEST_LIST = [ # randommap enabled
139 "test_class": StridedTest,
150 "test_class": StridedTest,
155 "zonerange": 16*1024*1024,
156 "zonesize": 16*1024*1024,
158 "size": 256*1024*1024,
159 "io_size": 256*1024*204,
161 "test_class": StridedTest,
172 "test_class": StridedTest,
177 "zonerange": 16*1024*1024,
178 "zonesize": 32*1024*1024,
180 "size": 256*1024*1024,
181 "io_size": 256*1024*204,
183 "test_class": StridedTest,
194 "test_class": StridedTest,
199 "zonerange": 16*1024*1024,
200 "zonesize": 8*1024*1024,
202 "size": 256*1024*1024,
203 "io_size": 256*1024*204,
205 "test_class": StridedTest,
211 "random_generator": "lfsr",
212 "zonerange": 4096*1024,
213 "zonesize": 4096*1024,
215 "offset": 8*4096*1024,
216 "size": 16*4096*1024,
217 "io_size": 16*4096*1024,
219 "test_class": StridedTest,
224 "random_generator": "lfsr",
225 "zonerange": 4096*1024,
226 "zonesize": 4096*1024,
228 "size": 16*4096*1024,
229 "io_size": 16*4096*1024,
231 "test_class": StridedTest,
236 "random_generator": "lfsr",
237 "zonerange": 16*1024*1024,
238 "zonesize": 16*1024*1024,
240 "size": 256*1024*1024,
241 "io_size": 256*1024*204,
243 "test_class": StridedTest,
248 "random_generator": "lfsr",
249 "zonerange": 4096*1024,
250 "zonesize": 4*4096*1024,
252 "size": 16*4096*1024,
253 "io_size": 16*4096*1024,
255 "test_class": StridedTest,
260 "random_generator": "lfsr",
261 "zonerange": 16*1024*1024,
262 "zonesize": 32*1024*1024,
264 "size": 256*1024*1024,
265 "io_size": 256*1024*204,
267 "test_class": StridedTest,
272 "random_generator": "lfsr",
273 "zonerange": 8192*1024,
274 "zonesize": 4096*1024,
276 "size": 16*4096*1024,
277 "io_size": 16*4096*1024,
279 "test_class": StridedTest,
284 "random_generator": "lfsr",
285 "zonerange": 16*1024*1024,
286 "zonesize": 8*1024*1024,
288 "size": 256*1024*1024,
289 "io_size": 256*1024*204,
291 "test_class": StridedTest,
305 "test_class": StridedTest,
317 "test_class": StridedTest,
323 "zonerange": 16*1024*1024,
324 "zonesize": 16*1024*1024,
326 "size": 256*1024*1024,
327 "io_size": 256*1024*204,
329 "test_class": StridedTest,
341 "test_class": StridedTest,
347 "zonerange": 16*1024*1024,
348 "zonesize": 32*1024*1024,
350 "size": 256*1024*1024,
351 "io_size": 256*1024*204,
353 "test_class": StridedTest,
365 "test_class": StridedTest,
371 "zonerange": 16*1024*1024,
372 "zonesize": 8*1024*1024,
374 "size": 256*1024*1024,
375 "io_size": 256*1024*1024,
377 "test_class": StridedTest,
383 """Parse command-line arguments."""
385 parser = argparse.ArgumentParser()
386 parser.add_argument('-f', '--fio', help='path to file executable (e.g., ./fio)')
387 parser.add_argument('-a', '--artifact-root', help='artifact root directory')
388 parser.add_argument('-s', '--skip', nargs='+', type=int,
389 help='list of test(s) to skip')
390 parser.add_argument('-o', '--run-only', nargs='+', type=int,
391 help='list of test(s) to run, skipping all others')
392 parser.add_argument('--dut',
393 help='target file/device to test.')
394 args = parser.parse_args()
400 """Run zonemode=strided tests."""
404 artifact_root = args.artifact_root if args.artifact_root else \
405 f"strided-test-{time.strftime('%Y%m%d-%H%M%S')}"
406 os.mkdir(artifact_root)
407 print(f"Artifact directory is {artifact_root}")
410 fio_path = str(Path(args.fio).absolute())
413 print(f"fio path is {fio_path}")
416 statinfo = os.stat(args.dut)
417 filesize = statinfo.st_size
419 f = os.open(args.dut, os.O_RDONLY)
420 filesize = os.lseek(f, 0, os.SEEK_END)
423 for test in TEST_LIST:
425 test['fio_opts']['filename'] = os.path.abspath(args.dut)
426 test['fio_opts']['filesize'] = filesize
428 test['fio_opts']['filesize'] = test['fio_opts']['size']
431 'fio_path': fio_path,
432 'fio_root': str(Path(__file__).absolute().parent.parent),
433 'artifact_root': artifact_root,
434 'basename': 'strided',
437 _, failed, _ = run_fio_tests(TEST_LIST, test_env, args)
441 if __name__ == '__main__':