]>
Commit | Line | Data |
---|---|---|
11fdf7f2 | 1 | #!/usr/bin/env python3 |
7c673cae | 2 | |
11fdf7f2 | 3 | from subprocess import check_call, call, check_output, Popen, PIPE, CalledProcessError |
7c673cae FG |
4 | import re |
5 | import sys | |
6 | import signal | |
7 | ||
8 | fio_template = """ | |
9 | [global] | |
10 | thread=1 | |
11 | invalidate=1 | |
12 | rw=%(testtype)s | |
13 | time_based=1 | |
14 | runtime=%(runtime)s | |
15 | ioengine=libaio | |
16 | direct=1 | |
17 | bs=%(blocksize)d | |
18 | iodepth=%(iodepth)d | |
19 | %(verify)s | |
20 | verify_dump=1 | |
21 | ||
22 | """ | |
23 | ||
24 | verify_template = """ | |
25 | do_verify=1 | |
26 | verify=meta | |
27 | verify_pattern="meta" | |
28 | """ | |
29 | ||
30 | ||
31 | fio_job_template = """ | |
32 | [job%(jobnumber)d] | |
33 | filename=%(device)s | |
34 | ||
35 | """ | |
36 | ||
11fdf7f2 | 37 | |
7c673cae FG |
38 | def interrupt_handler(signum, frame): |
39 | fio.terminate() | |
11fdf7f2 | 40 | print("FIO terminated") |
7c673cae FG |
41 | sys.exit(0) |
42 | ||
11fdf7f2 | 43 | |
7c673cae FG |
44 | def main(): |
45 | ||
46 | global fio | |
47 | if (len(sys.argv) < 5): | |
11fdf7f2 TL |
48 | print("usage:") |
49 | print(" " + sys.argv[0] + " <io_size> <queue_depth> <test_type> <runtime>") | |
50 | print("advanced usage:") | |
51 | print("If you want to run fio with verify, please add verify string after runtime.") | |
52 | print("Currently fio.py only support write rw randwrite randrw with verify enabled.") | |
7c673cae FG |
53 | sys.exit(1) |
54 | ||
55 | io_size = int(sys.argv[1]) | |
56 | queue_depth = int(sys.argv[2]) | |
57 | test_type = sys.argv[3] | |
58 | runtime = sys.argv[4] | |
59 | if len(sys.argv) > 5: | |
60 | verify = True | |
61 | else: | |
62 | verify = False | |
63 | ||
64 | devices = get_target_devices() | |
11fdf7f2 | 65 | print("Found devices: ", devices) |
7c673cae FG |
66 | |
67 | # configure_devices(devices) | |
11fdf7f2 TL |
68 | try: |
69 | fio_executable = check_output("which fio", shell=True).split()[0] | |
70 | except CalledProcessError as e: | |
71 | sys.stderr.write(str(e)) | |
72 | sys.stderr.write("\nCan't find the fio binary, please install it.\n") | |
73 | sys.exit(1) | |
7c673cae FG |
74 | |
75 | device_paths = ['/dev/' + dev for dev in devices] | |
11fdf7f2 | 76 | print(device_paths) |
7c673cae FG |
77 | sys.stdout.flush() |
78 | signal.signal(signal.SIGTERM, interrupt_handler) | |
79 | signal.signal(signal.SIGINT, interrupt_handler) | |
80 | fio = Popen([fio_executable, '-'], stdin=PIPE) | |
81 | fio.communicate(create_fio_config(io_size, queue_depth, device_paths, test_type, runtime, verify)) | |
82 | fio.stdin.close() | |
83 | rc = fio.wait() | |
11fdf7f2 | 84 | print("FIO completed with code %d\n" % rc) |
7c673cae FG |
85 | sys.stdout.flush() |
86 | sys.exit(rc) | |
87 | ||
11fdf7f2 | 88 | |
7c673cae | 89 | def get_target_devices(): |
11fdf7f2 | 90 | output = str(check_output('lsblk -l -o NAME', shell=True).decode()) |
7c673cae FG |
91 | return re.findall("(nvme[0-9]+n[0-9]+)\n", output) |
92 | ||
11fdf7f2 | 93 | |
7c673cae FG |
94 | def create_fio_config(size, q_depth, devices, test, run_time, verify): |
95 | if not verify: | |
96 | verifyfio = "" | |
97 | else: | |
98 | verifyfio = verify_template | |
99 | fiofile = fio_template % {"blocksize": size, "iodepth": q_depth, | |
100 | "testtype": test, "runtime": run_time, "verify": verifyfio} | |
101 | for (i, dev) in enumerate(devices): | |
102 | fiofile += fio_job_template % {"jobnumber": i, "device": dev} | |
11fdf7f2 TL |
103 | return fiofile.encode() |
104 | ||
7c673cae FG |
105 | |
106 | def set_device_parameter(devices, filename_template, value): | |
107 | for dev in devices: | |
108 | filename = filename_template % dev | |
109 | f = open(filename, 'r+b') | |
110 | f.write(value) | |
111 | f.close() | |
112 | ||
11fdf7f2 | 113 | |
7c673cae FG |
114 | def configure_devices(devices): |
115 | set_device_parameter(devices, "/sys/block/%s/queue/nomerges", "2") | |
116 | set_device_parameter(devices, "/sys/block/%s/queue/nr_requests", "128") | |
117 | requested_qd = 128 | |
118 | qd = requested_qd | |
119 | while qd > 0: | |
120 | try: | |
121 | set_device_parameter(devices, "/sys/block/%s/device/queue_depth", str(qd)) | |
122 | break | |
123 | except IOError: | |
124 | qd = qd - 1 | |
125 | if qd == 0: | |
11fdf7f2 | 126 | print("Could not set block device queue depths.") |
7c673cae | 127 | else: |
11fdf7f2 | 128 | print("Requested queue_depth {} but only {} is supported.".format(str(requested_qd), str(qd))) |
7c673cae FG |
129 | set_device_parameter(devices, "/sys/block/%s/queue/scheduler", "noop") |
130 | ||
11fdf7f2 | 131 | |
7c673cae FG |
132 | if __name__ == "__main__": |
133 | main() |