]> git.proxmox.com Git - ceph.git/blob - ceph/src/spdk/test/vhost/common/run_fio.py
import 15.2.0 Octopus source
[ceph.git] / ceph / src / spdk / test / vhost / common / run_fio.py
1 #!/usr/bin/env python3
2
3 import os
4 import sys
5 import getopt
6 import subprocess
7 import signal
8 import re
9
10 fio_bin = "fio"
11
12
13 def show_help():
14 print("""Usage: {} run_fio.py [options] [args]
15 Description:
16 Run FIO job file 'fio.job' on remote machines.
17 NOTE: The job file must exist on remote machines on '/root/' directory.
18 Args:
19 [VMs] (ex. vm1_IP:vm1_port:vm1_disk1:vm_disk2,vm2_IP:vm2_port:vm2_disk1,etc...)
20 Options:
21 -h, --help Show this message.
22 -j, --job-file Paths to file with FIO job configuration on remote host.
23 -f, --fio-bin Location of FIO binary on local host (Default "fio")
24 -o, --out Directory used to save generated job files and
25 files with test results
26 -J, --json Use JSON format for output
27 -p, --perf-vmex Enable aggregating statistic for VMEXITS for VMs
28 """.format(os.path.split(sys.executable)[-1]))
29
30
31 def exec_cmd(cmd, blocking):
32 # Print result to STDOUT for now, we don't have json support yet.
33 p = subprocess.Popen(cmd.split(" "), stdout=subprocess.PIPE,
34 stderr=subprocess.STDOUT, stdin=subprocess.PIPE)
35 if blocking is True:
36 out, _ = p.communicate()
37 return p.returncode, out.decode()
38 return p
39
40
41 def save_file(path, mode, contents):
42 with open(path, mode) as fh:
43 fh.write(contents)
44 fh.close()
45
46
47 def run_fio(vms, fio_cfg_fname, out_path, perf_vmex=False, json=False):
48 global fio_bin
49 job_name = os.path.splitext(os.path.basename(fio_cfg_fname))[0]
50
51 # Build command for FIO
52 fio_cmd = " ".join([fio_bin, "--eta=never"])
53 if json:
54 fio_cmd = " ".join([fio_bin, "--output-format=json"])
55 for vm in vms:
56 # vm[0] = IP address, vm[1] = Port number
57 fio_cmd = " ".join([fio_cmd,
58 "--client={vm_ip},{vm_port}".format(vm_ip=vm[0], vm_port=vm[1]),
59 "--remote-config {cfg}".format(cfg=fio_cfg_fname)])
60 print(fio_cmd)
61
62 if perf_vmex:
63 perf_dir = os.path.join(out_path, "perf_stats")
64 try:
65 os.mkdir(perf_dir)
66 except OSError:
67 pass
68
69 # Start gathering perf statistics for host and VM guests
70 perf_rec_file = os.path.join(perf_dir, "perf.data.kvm")
71 perf_run_cmd = "perf kvm --host --guest " + \
72 "-o {0} stat record -a".format(perf_rec_file)
73 print(perf_run_cmd)
74 perf_p = exec_cmd(perf_run_cmd, blocking=False)
75
76 # Run FIO test on VMs
77 rc, out = exec_cmd(fio_cmd, blocking=True)
78
79 # if for some reason output contains lines with "eta" - remove them
80 out = re.sub(r'.+\[eta\s+\d{2}m:\d{2}s\]', '', out)
81
82 print(out)
83
84 if rc != 0:
85 print("ERROR! While executing FIO jobs - RC: {rc}".format(rc=rc, out=out))
86 sys.exit(rc)
87 else:
88 save_file(os.path.join(out_path, ".".join([job_name, "log"])), "w", out)
89
90 if perf_vmex:
91 # Stop gathering perf statistics and prepare some result files
92 perf_p.send_signal(signal.SIGINT)
93 perf_p.wait()
94
95 perf_stat_cmd = "perf kvm --host -i {perf_rec} stat report --event vmexit"\
96 .format(perf_rec=perf_rec_file)
97
98 rc, out = exec_cmd(" ".join([perf_stat_cmd, "--event vmexit"]),
99 blocking=True)
100 print("VMexit host stats:")
101 print("{perf_out}".format(perf_out=out))
102 save_file(os.path.join(perf_dir, "vmexit_stats_" + job_name),
103 "w", "{perf_out}".format(perf_out=out))
104 try:
105 os.remove(perf_rec_file)
106 except OSError:
107 pass
108
109
110 def main():
111 global fio_bin
112
113 abspath = os.path.abspath(__file__)
114 dname = os.path.dirname(abspath)
115
116 vms = []
117 fio_cfg = None
118 out_dir = None
119 perf_vmex = False
120 json = False
121
122 try:
123 opts, args = getopt.getopt(sys.argv[1:], "hJj:f:o:p",
124 ["help", "job-file=", "fio-bin=",
125 "out=", "perf-vmex", "json"])
126 except getopt.GetoptError:
127 show_help()
128 sys.exit(1)
129
130 if len(args) < 1:
131 show_help()
132 sys.exit(1)
133
134 for o, a in opts:
135 if o in ("-j", "--job-file"):
136 fio_cfg = a
137 elif o in ("-h", "--help"):
138 show_help()
139 sys.exit(1)
140 elif o in ("-p", "--perf-vmex"):
141 perf_vmex = True
142 elif o in ("-o", "--out"):
143 out_dir = a
144 elif o in ("-f", "--fio-bin"):
145 fio_bin = a
146 elif o in ("-J", "--json"):
147 json = True
148
149 if fio_cfg is None:
150 print("ERROR! No FIO job provided!")
151 sys.exit(1)
152
153 if out_dir is None or not os.path.exists(out_dir):
154 print("ERROR! Folder {out_dir} does not exist ".format(out_dir=out_dir))
155 sys.exit(1)
156
157 # Get IP, port and fio 'filename' information from positional args
158 for arg in args[0].split(","):
159 _ = arg.split(":")
160 ip, port, filenames = _[0], _[1], ":".join(_[2:])
161 vms.append((ip, port, filenames))
162
163 print("Running job file: {0}".format(fio_cfg))
164 run_fio(vms, fio_cfg, out_dir, perf_vmex, json)
165
166
167 if __name__ == "__main__":
168 sys.exit(main())