Merge branch 'windows-s_issock' of https://github.com/aclamk/fio
[fio.git] / t / sgunmap-test.py
1 #!/usr/bin/python2.7
2 # Note: this script is python2 and python 3 compatible.
3 #
4 # sgunmap-test.py
5 #
6 # Limited functonality test for trim workloads using fio's sg ioengine
7 # This checks only the three sets of reported iodepths
8 #
9 # !!!WARNING!!!
10 # This script carries out destructive tests. Be sure that
11 # there is no data you want to keep on the supplied devices.
12 #
13 # USAGE
14 # sgunmap-test.py char-device block-device fio-executable
15 #
16 # EXAMPLE
17 # t/sgunmap-test.py /dev/sg1 /dev/sdb ./fio
18 #
19 # REQUIREMENTS
20 # Python 2.6+
21 #
22 # TEST MATRIX
23 # For both char-dev and block-dev these are the expected
24 # submit/complete IO depths
25 #
26 #                       blockdev                chardev
27 #                       iodepth                 iodepth
28 # R QD1                 sub/comp: 1-4=100%      sub/comp: 1-4=100%
29 # W QD1                 sub/comp: 1-4=100%      sub/comp: 1-4=100%
30 # T QD1                 sub/comp: 1-4=100%      sub/comp: 1-4=100%
31 #
32 # R QD16, batch8        sub/comp: 1-4=100%      sub/comp: 1-4=100%
33 # W QD16, batch8        sub/comp: 1-4=100%      sub/comp: 1-4=100%
34 # T QD16, batch8        sub/comp: 1-4=100%      sub/comp: 5-8=100%
35 #
36 # R QD16, batch16       sub/comp: 1-4=100%      sub/comp: 1-4=100%
37 # W QD16, batch16       sub/comp: 1-4=100%      sub/comp: 1-4=100%
38 # T QD16, batch16       sub/comp: 1-4=100%      sub/comp: 9-16=100%
39 #
40
41 from __future__ import absolute_import
42 from __future__ import print_function
43 import sys
44 import json
45 import argparse
46 import traceback
47 import subprocess
48 from six.moves import range
49
50
51 def parse_args():
52     parser = argparse.ArgumentParser()
53     parser.add_argument('chardev',
54                         help='character device target (e.g., /dev/sg0)')
55     parser.add_argument('blockdev',
56                         help='block device target (e.g., /dev/sda)')
57     parser.add_argument('fio',
58                         help='path to fio executable (e.g., ./fio)')
59     args = parser.parse_args()
60
61     return args
62
63 #
64 # With block devices,
65 #     iodepth = 1 always
66 #     submit = complete = 1-4 always
67 # With character devices,
68 # RW
69 #     iodepth = qd
70 #     submit = 1-4
71 #     complete = 1-4 except for the IOs in flight
72 #                when the job is ending
73 # T
74 #     iodepth = qd
75 #     submit = qdbatch
76 #     complete = qdbatch except for the IOs in flight
77 #                when the job is ending
78 #
79
80
81 def check(jsondata, parameters, block, qd, qdbatch, rw):
82     iodepth = jsondata['iodepth_level']
83     submit = jsondata['iodepth_submit']
84     complete = jsondata['iodepth_complete']
85
86     try:
87         if block:
88             assert iodepth['1'] == 100.0
89             assert submit['4'] == 100.0
90             assert complete['4'] == 100.0
91         elif 'read' in rw or 'write' in rw:
92             assert iodepth[str(qd)] > 99.9
93             assert submit['4'] == 100.0
94             assert complete['4'] > 99.9
95         else:
96             if qdbatch <= 4:
97                 batchkey = '4'
98             elif qdbatch > 64:
99                 batchkey = '>=64'
100             else:
101                 batchkey = str(qdbatch)
102             if qd >= 64:
103                 qdkey = ">=64"
104             else:
105                 qdkey = str(qd)
106             assert iodepth[qdkey] > 99
107             assert submit[batchkey] == 100.0
108             assert complete[batchkey] > 99
109     except AssertionError:
110         print("Assertion failed")
111         traceback.print_exc()
112         print(jsondata)
113         return
114
115     print("**********passed*********")
116
117
118 def runalltests(args, qd, batch):
119     block = False
120     for dev in [args.chardev, args.blockdev]:
121         for rw in ["randread", "randwrite", "randtrim"]:
122             parameters = ["--name=test",
123                            "--time_based",
124                            "--runtime=30s",
125                            "--output-format=json",
126                            "--ioengine=sg",
127                            "--rw={0}".format(rw),
128                            "--filename={0}".format(dev),
129                            "--iodepth={0}".format(qd),
130                            "--iodepth_batch={0}".format(batch)]
131
132             print(parameters)
133             output = subprocess.check_output([args.fio] + parameters)
134             jsondata = json.loads(output)
135             jobdata = jsondata['jobs'][0]
136             check(jobdata, parameters, block, qd, batch, rw)
137         block = True
138
139
140 def runcdevtrimtest(args, qd, batch):
141     parameters = ["--name=test",
142                    "--time_based",
143                    "--runtime=30s",
144                    "--output-format=json",
145                    "--ioengine=sg",
146                    "--rw=randtrim",
147                    "--filename={0}".format(args.chardev),
148                    "--iodepth={0}".format(qd),
149                    "--iodepth_batch={0}".format(batch)]
150
151     print(parameters)
152     output = subprocess.check_output([args.fio] + parameters)
153     jsondata = json.loads(output)
154     jobdata = jsondata['jobs'][0]
155     check(jobdata, parameters, False, qd, batch, "randtrim")
156
157
158 if __name__ == '__main__':
159     args = parse_args()
160
161     runcdevtrimtest(args, 32, 2)
162     runcdevtrimtest(args, 32, 4)
163     runcdevtrimtest(args, 32, 8)
164     runcdevtrimtest(args, 64, 4)
165     runcdevtrimtest(args, 64, 8)
166     runcdevtrimtest(args, 64, 16)
167     runcdevtrimtest(args, 128, 8)
168     runcdevtrimtest(args, 128, 16)
169     runcdevtrimtest(args, 128, 32)
170
171     runalltests(args, 1, 1)
172     runalltests(args, 16, 2)
173     runalltests(args, 16, 16)