Commit | Line | Data |
---|---|---|
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 |
31 | import os |
32 | import sys | |
5a36d0e4 | 33 | import time |
6d5af490 | 34 | import argparse |
5a36d0e4 VF |
35 | from pathlib import Path |
36 | from fiotestlib import FioJobCmdTest, run_fio_tests | |
6d5af490 VF |
37 | |
38 | ||
5a36d0e4 VF |
39 | class 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 | |
130 | TEST_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 | ||
384 | def 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 | ||
401 | def 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 | ||
443 | if __name__ == '__main__': | |
444 | main() |