5 # Test zonemode=strided. This uses the null ioengine when no file is
6 # specified. If a file is specified, use it for randdom read testing.
7 # Some of the zoneranges in the tests are 16MiB. So when using a file
8 # a minimum size of 32MiB is recommended.
11 # python strided.py fio-executable [-f file/device]
14 # python t/strided.py ./fio
15 # python t/strided.py ./fio -f /dev/sda
16 # dd if=/dev/zero of=temp bs=1M count=32
17 # python t/strided.py ./fio -f temp
24 # --zonemode=strided, zoneskip unset
25 # w/ randommap and LFSR
26 # zonesize=zonerange all blocks in zonerange touched
27 # zonesize>zonerange all blocks touched and roll-over back into zone
28 # zonesize<zonerange all blocks inside zone
30 # w/o randommap all blocks inside zone
33 from __future__ import absolute_import
34 from __future__ import print_function
42 parser = argparse.ArgumentParser()
43 parser.add_argument('fio',
44 help='path to fio executable (e.g., ./fio)')
45 parser.add_argument('-f', '--filename', help="file/device to test")
46 args = parser.parse_args()
51 def run_fio(fio, test, index):
60 "--write_iops_log={0}{1:03d}".format(filename, index),
61 "--output={0}{1:03d}.out".format(filename, index),
62 "--zonerange={zonerange}".format(**test),
63 "--zonesize={zonesize}".format(**test),
64 "--bs={bs}".format(**test),
66 if 'norandommap' in test:
67 fio_args.append('--norandommap')
68 if 'random_generator' in test:
69 fio_args.append('--random_generator={random_generator}'.format(**test))
71 fio_args.append('--offset={offset}'.format(**test))
72 if 'filename' in test:
73 fio_args.append('--filename={filename}'.format(**test))
74 fio_args.append('--filesize={filesize})'.format(**test))
76 fio_args.append('--ioengine=null')
77 fio_args.append('--size={size}'.format(**test))
78 fio_args.append('--io_size={io_size}'.format(**test))
79 fio_args.append('--filesize={size})'.format(**test))
81 output = subprocess.check_output([fio] + fio_args, universal_newlines=True)
83 f = open("{0}{1:03d}_iops.1.log".format(filename, index), "r")
90 def check_output(iops_log, test):
91 zonestart = 0 if 'offset' not in test else test['offset']
92 iospersize = test['zonesize'] / test['bs']
93 iosperrange = test['zonerange'] / test['bs']
95 lines = iops_log.split('\n')
102 if iosperzone == iospersize:
103 # time to move to a new zone
106 zonestart += test['zonerange']
107 if zonestart >= test['filesize']:
108 zonestart = 0 if 'offset' not in test else test['offset']
110 iosperzone = iosperzone + 1
111 tokens = line.split(',')
112 offset = int(tokens[4])
113 if offset < zonestart or offset >= zonestart + test['zonerange']:
114 print("Offset {0} outside of zone starting at {1}".format(
118 # skip next section if norandommap is enabled with no
119 # random_generator or with a random_generator != lfsr
120 if 'norandommap' in test:
121 if 'random_generator' in test:
122 if test['random_generator'] != 'lfsr':
127 # we either have a random map enabled or we
129 # so all blocks should be unique and we should have
130 # covered the entire zone when iosperzone % iosperrange == 0
131 block = (offset - zonestart) / test['bs']
133 print("Offset {0} in zone already touched".format(offset))
137 if iosperzone % iosperrange == 0:
138 if len(zoneset) != iosperrange:
139 print("Expected {0} blocks in zone but only saw {1}".format(
140 iosperrange, len(zoneset)))
147 if __name__ == '__main__':
150 tests = [ # randommap enabled
167 "zonerange": 16*1024*1024,
168 "zonesize": 16*1024*1024,
170 "size": 256*1024*1024,
171 "io_size": 256*1024*204,
181 "zonerange": 16*1024*1024,
182 "zonesize": 32*1024*1024,
184 "size": 256*1024*1024,
185 "io_size": 256*1024*204,
195 "zonerange": 16*1024*1024,
196 "zonesize": 8*1024*1024,
198 "size": 256*1024*1024,
199 "io_size": 256*1024*204,
203 "random_generator": "lfsr",
204 "zonerange": 4096*1024,
205 "zonesize": 4096*1024,
207 "offset": 8*4096*1024,
208 "size": 16*4096*1024,
209 "io_size": 16*4096*1024,
212 "random_generator": "lfsr",
213 "zonerange": 4096*1024,
214 "zonesize": 4096*1024,
216 "size": 16*4096*1024,
217 "io_size": 16*4096*1024,
220 "random_generator": "lfsr",
221 "zonerange": 16*1024*1024,
222 "zonesize": 16*1024*1024,
224 "size": 256*1024*1024,
225 "io_size": 256*1024*204,
228 "random_generator": "lfsr",
229 "zonerange": 4096*1024,
230 "zonesize": 4*4096*1024,
232 "size": 16*4096*1024,
233 "io_size": 16*4096*1024,
236 "random_generator": "lfsr",
237 "zonerange": 16*1024*1024,
238 "zonesize": 32*1024*1024,
240 "size": 256*1024*1024,
241 "io_size": 256*1024*204,
244 "random_generator": "lfsr",
245 "zonerange": 8192*1024,
246 "zonesize": 4096*1024,
248 "size": 16*4096*1024,
249 "io_size": 16*4096*1024,
252 "random_generator": "lfsr",
253 "zonerange": 16*1024*1024,
254 "zonesize": 8*1024*1024,
256 "size": 256*1024*1024,
257 "io_size": 256*1024*204,
279 "zonerange": 16*1024*1024,
280 "zonesize": 16*1024*1024,
282 "size": 256*1024*1024,
283 "io_size": 256*1024*204,
295 "zonerange": 16*1024*1024,
296 "zonesize": 32*1024*1024,
298 "size": 256*1024*1024,
299 "io_size": 256*1024*204,
311 "zonerange": 16*1024*1024,
312 "zonesize": 8*1024*1024,
314 "size": 256*1024*1024,
315 "io_size": 256*1024*1024,
325 statinfo = os.stat(args.filename)
326 filesize = statinfo.st_size
328 f = os.open(args.filename, os.O_RDONLY)
329 filesize = os.lseek(f, 0, os.SEEK_END)
334 test['filename'] = args.filename
335 test['filesize'] = filesize
337 test['filesize'] = test['size']
338 iops_log = run_fio(args.fio, test, index)
339 status = check_output(iops_log, test)
340 print("Test {0} {1}".format(index, ("PASSED" if status else "FAILED")))
347 print("{0} tests passed, {1} failed".format(passed, failed))