2 # Note: this script is python2 and python3 compatible.
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 32MiB 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=32
18 # python t/strided.py ./fio -f temp
25 # --zonemode=strided, zoneskip unset
26 # w/ randommap and LFSR
27 # zonesize=zonerange all blocks in zonerange touched
28 # zonesize>zonerange all blocks touched and roll-over back into zone
29 # zonesize<zonerange all blocks inside zone
31 # w/o randommap all blocks inside zone
34 from __future__ import absolute_import
35 from __future__ import print_function
43 parser = argparse.ArgumentParser()
44 parser.add_argument('fio',
45 help='path to fio executable (e.g., ./fio)')
46 parser.add_argument('-f', '--filename', help="file/device to test")
47 args = parser.parse_args()
52 def run_fio(fio, test, index):
61 "--write_iops_log={0}{1:03d}".format(filename, index),
62 "--output={0}{1:03d}.out".format(filename, index),
63 "--zonerange={zonerange}".format(**test),
64 "--zonesize={zonesize}".format(**test),
65 "--bs={bs}".format(**test),
67 if 'norandommap' in test:
68 fio_args.append('--norandommap')
69 if 'random_generator' in test:
70 fio_args.append('--random_generator={random_generator}'.format(**test))
72 fio_args.append('--offset={offset}'.format(**test))
73 if 'filename' in test:
74 fio_args.append('--filename={filename}'.format(**test))
75 fio_args.append('--filesize={filesize})'.format(**test))
77 fio_args.append('--ioengine=null')
78 fio_args.append('--size={size}'.format(**test))
79 fio_args.append('--io_size={io_size}'.format(**test))
80 fio_args.append('--filesize={size})'.format(**test))
82 output = subprocess.check_output([fio] + fio_args, universal_newlines=True)
84 f = open("{0}{1:03d}_iops.1.log".format(filename, index), "r")
91 def check_output(iops_log, test):
92 zonestart = 0 if 'offset' not in test else test['offset']
93 iospersize = test['zonesize'] / test['bs']
94 iosperrange = test['zonerange'] / test['bs']
96 lines = iops_log.split('\n')
103 if iosperzone == iospersize:
104 # time to move to a new zone
107 zonestart += test['zonerange']
108 if zonestart >= test['filesize']:
109 zonestart = 0 if 'offset' not in test else test['offset']
111 iosperzone = iosperzone + 1
112 tokens = line.split(',')
113 offset = int(tokens[4])
114 if offset < zonestart or offset >= zonestart + test['zonerange']:
115 print("Offset {0} outside of zone starting at {1}".format(
119 # skip next section if norandommap is enabled with no
120 # random_generator or with a random_generator != lfsr
121 if 'norandommap' in test:
122 if 'random_generator' in test:
123 if test['random_generator'] != 'lfsr':
128 # we either have a random map enabled or we
130 # so all blocks should be unique and we should have
131 # covered the entire zone when iosperzone % iosperrange == 0
132 block = (offset - zonestart) / test['bs']
134 print("Offset {0} in zone already touched".format(offset))
138 if iosperzone % iosperrange == 0:
139 if len(zoneset) != iosperrange:
140 print("Expected {0} blocks in zone but only saw {1}".format(
141 iosperrange, len(zoneset)))
148 if __name__ == '__main__':
151 tests = [ # randommap enabled
168 "zonerange": 16*1024*1024,
169 "zonesize": 16*1024*1024,
171 "size": 256*1024*1024,
172 "io_size": 256*1024*204,
182 "zonerange": 16*1024*1024,
183 "zonesize": 32*1024*1024,
185 "size": 256*1024*1024,
186 "io_size": 256*1024*204,
196 "zonerange": 16*1024*1024,
197 "zonesize": 8*1024*1024,
199 "size": 256*1024*1024,
200 "io_size": 256*1024*204,
204 "random_generator": "lfsr",
205 "zonerange": 4096*1024,
206 "zonesize": 4096*1024,
208 "offset": 8*4096*1024,
209 "size": 16*4096*1024,
210 "io_size": 16*4096*1024,
213 "random_generator": "lfsr",
214 "zonerange": 4096*1024,
215 "zonesize": 4096*1024,
217 "size": 16*4096*1024,
218 "io_size": 16*4096*1024,
221 "random_generator": "lfsr",
222 "zonerange": 16*1024*1024,
223 "zonesize": 16*1024*1024,
225 "size": 256*1024*1024,
226 "io_size": 256*1024*204,
229 "random_generator": "lfsr",
230 "zonerange": 4096*1024,
231 "zonesize": 4*4096*1024,
233 "size": 16*4096*1024,
234 "io_size": 16*4096*1024,
237 "random_generator": "lfsr",
238 "zonerange": 16*1024*1024,
239 "zonesize": 32*1024*1024,
241 "size": 256*1024*1024,
242 "io_size": 256*1024*204,
245 "random_generator": "lfsr",
246 "zonerange": 8192*1024,
247 "zonesize": 4096*1024,
249 "size": 16*4096*1024,
250 "io_size": 16*4096*1024,
253 "random_generator": "lfsr",
254 "zonerange": 16*1024*1024,
255 "zonesize": 8*1024*1024,
257 "size": 256*1024*1024,
258 "io_size": 256*1024*204,
280 "zonerange": 16*1024*1024,
281 "zonesize": 16*1024*1024,
283 "size": 256*1024*1024,
284 "io_size": 256*1024*204,
296 "zonerange": 16*1024*1024,
297 "zonesize": 32*1024*1024,
299 "size": 256*1024*1024,
300 "io_size": 256*1024*204,
312 "zonerange": 16*1024*1024,
313 "zonesize": 8*1024*1024,
315 "size": 256*1024*1024,
316 "io_size": 256*1024*1024,
326 statinfo = os.stat(args.filename)
327 filesize = statinfo.st_size
329 f = os.open(args.filename, os.O_RDONLY)
330 filesize = os.lseek(f, 0, os.SEEK_END)
335 test['filename'] = args.filename
336 test['filesize'] = filesize
338 test['filesize'] = test['size']
339 iops_log = run_fio(args.fio, test, index)
340 status = check_output(iops_log, test)
341 print("Test {0} {1}".format(index, ("PASSED" if status else "FAILED")))
348 print("{0} tests passed, {1} failed".format(passed, failed))