Commit | Line | Data |
---|---|---|
8629f5f5 | 1 | #!/usr/bin/env python3 |
15835530 VF |
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 | |
15835530 VF |
48 | |
49 | ||
50 | def parse_args(): | |
51 | parser = argparse.ArgumentParser() | |
52 | parser.add_argument('chardev', | |
53 | help='character device target (e.g., /dev/sg0)') | |
54 | parser.add_argument('blockdev', | |
55 | help='block device target (e.g., /dev/sda)') | |
56 | parser.add_argument('fio', | |
57 | help='path to fio executable (e.g., ./fio)') | |
58 | args = parser.parse_args() | |
59 | ||
60 | return args | |
61 | ||
62 | # | |
63 | # With block devices, | |
64 | # iodepth = 1 always | |
65 | # submit = complete = 1-4 always | |
66 | # With character devices, | |
67 | # RW | |
68 | # iodepth = qd | |
69 | # submit = 1-4 | |
70 | # complete = 1-4 except for the IOs in flight | |
71 | # when the job is ending | |
72 | # T | |
73 | # iodepth = qd | |
74 | # submit = qdbatch | |
75 | # complete = qdbatch except for the IOs in flight | |
76 | # when the job is ending | |
77 | # | |
78 | ||
79 | ||
80 | def check(jsondata, parameters, block, qd, qdbatch, rw): | |
81 | iodepth = jsondata['iodepth_level'] | |
82 | submit = jsondata['iodepth_submit'] | |
83 | complete = jsondata['iodepth_complete'] | |
84 | ||
85 | try: | |
86 | if block: | |
87 | assert iodepth['1'] == 100.0 | |
88 | assert submit['4'] == 100.0 | |
89 | assert complete['4'] == 100.0 | |
90 | elif 'read' in rw or 'write' in rw: | |
91 | assert iodepth[str(qd)] > 99.9 | |
92 | assert submit['4'] == 100.0 | |
93 | assert complete['4'] > 99.9 | |
94 | else: | |
95 | if qdbatch <= 4: | |
96 | batchkey = '4' | |
97 | elif qdbatch > 64: | |
98 | batchkey = '>=64' | |
99 | else: | |
100 | batchkey = str(qdbatch) | |
101 | if qd >= 64: | |
102 | qdkey = ">=64" | |
103 | else: | |
104 | qdkey = str(qd) | |
105 | assert iodepth[qdkey] > 99 | |
106 | assert submit[batchkey] == 100.0 | |
107 | assert complete[batchkey] > 99 | |
108 | except AssertionError: | |
109 | print("Assertion failed") | |
110 | traceback.print_exc() | |
111 | print(jsondata) | |
112 | return | |
113 | ||
114 | print("**********passed*********") | |
115 | ||
116 | ||
117 | def runalltests(args, qd, batch): | |
118 | block = False | |
119 | for dev in [args.chardev, args.blockdev]: | |
120 | for rw in ["randread", "randwrite", "randtrim"]: | |
121 | parameters = ["--name=test", | |
122 | "--time_based", | |
123 | "--runtime=30s", | |
124 | "--output-format=json", | |
125 | "--ioengine=sg", | |
126 | "--rw={0}".format(rw), | |
127 | "--filename={0}".format(dev), | |
128 | "--iodepth={0}".format(qd), | |
129 | "--iodepth_batch={0}".format(batch)] | |
130 | ||
131 | print(parameters) | |
132 | output = subprocess.check_output([args.fio] + parameters) | |
133 | jsondata = json.loads(output) | |
134 | jobdata = jsondata['jobs'][0] | |
135 | check(jobdata, parameters, block, qd, batch, rw) | |
136 | block = True | |
137 | ||
138 | ||
139 | def runcdevtrimtest(args, qd, batch): | |
140 | parameters = ["--name=test", | |
141 | "--time_based", | |
142 | "--runtime=30s", | |
143 | "--output-format=json", | |
144 | "--ioengine=sg", | |
145 | "--rw=randtrim", | |
146 | "--filename={0}".format(args.chardev), | |
147 | "--iodepth={0}".format(qd), | |
148 | "--iodepth_batch={0}".format(batch)] | |
149 | ||
150 | print(parameters) | |
151 | output = subprocess.check_output([args.fio] + parameters) | |
152 | jsondata = json.loads(output) | |
153 | jobdata = jsondata['jobs'][0] | |
154 | check(jobdata, parameters, False, qd, batch, "randtrim") | |
155 | ||
156 | ||
157 | if __name__ == '__main__': | |
158 | args = parse_args() | |
159 | ||
160 | runcdevtrimtest(args, 32, 2) | |
161 | runcdevtrimtest(args, 32, 4) | |
162 | runcdevtrimtest(args, 32, 8) | |
163 | runcdevtrimtest(args, 64, 4) | |
164 | runcdevtrimtest(args, 64, 8) | |
165 | runcdevtrimtest(args, 64, 16) | |
166 | runcdevtrimtest(args, 128, 8) | |
167 | runcdevtrimtest(args, 128, 16) | |
168 | runcdevtrimtest(args, 128, 32) | |
169 | ||
170 | runalltests(args, 1, 1) | |
171 | runalltests(args, 16, 2) | |
172 | runalltests(args, 16, 16) |