Merge remote-tracking branch 'remotes/stsquad/tags/pull-testing-and-python-021020...
[qemu/ar7.git] / tests / migration / guestperf / shell.py
blob5bcc066bb9815383813daf72ac8aa453eea11554
2 # Migration test command line shell integration
4 # Copyright (c) 2016 Red Hat, Inc.
6 # This library is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU Lesser General Public
8 # License as published by the Free Software Foundation; either
9 # version 2 of the License, or (at your option) any later version.
11 # This library is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 # Lesser General Public License for more details.
16 # You should have received a copy of the GNU Lesser General Public
17 # License along with this library; if not, see <http://www.gnu.org/licenses/>.
21 import argparse
22 import fnmatch
23 import os
24 import os.path
25 import platform
26 import sys
27 import logging
29 from guestperf.hardware import Hardware
30 from guestperf.engine import Engine
31 from guestperf.scenario import Scenario
32 from guestperf.comparison import COMPARISONS
33 from guestperf.plot import Plot
34 from guestperf.report import Report
37 class BaseShell(object):
39 def __init__(self):
40 parser = argparse.ArgumentParser(description="Migration Test Tool")
42 # Test args
43 parser.add_argument("--debug", dest="debug", default=False, action="store_true")
44 parser.add_argument("--verbose", dest="verbose", default=False, action="store_true")
45 parser.add_argument("--sleep", dest="sleep", default=15, type=int)
46 parser.add_argument("--binary", dest="binary", default="/usr/bin/qemu-system-x86_64")
47 parser.add_argument("--dst-host", dest="dst_host", default="localhost")
48 parser.add_argument("--kernel", dest="kernel", default="/boot/vmlinuz-%s" % platform.release())
49 parser.add_argument("--initrd", dest="initrd", default="tests/migration/initrd-stress.img")
50 parser.add_argument("--transport", dest="transport", default="unix")
53 # Hardware args
54 parser.add_argument("--cpus", dest="cpus", default=1, type=int)
55 parser.add_argument("--mem", dest="mem", default=1, type=int)
56 parser.add_argument("--src-cpu-bind", dest="src_cpu_bind", default="")
57 parser.add_argument("--src-mem-bind", dest="src_mem_bind", default="")
58 parser.add_argument("--dst-cpu-bind", dest="dst_cpu_bind", default="")
59 parser.add_argument("--dst-mem-bind", dest="dst_mem_bind", default="")
60 parser.add_argument("--prealloc-pages", dest="prealloc_pages", default=False)
61 parser.add_argument("--huge-pages", dest="huge_pages", default=False)
62 parser.add_argument("--locked-pages", dest="locked_pages", default=False)
64 self._parser = parser
66 def get_engine(self, args):
67 return Engine(binary=args.binary,
68 dst_host=args.dst_host,
69 kernel=args.kernel,
70 initrd=args.initrd,
71 transport=args.transport,
72 sleep=args.sleep,
73 debug=args.debug,
74 verbose=args.verbose)
76 def get_hardware(self, args):
77 def split_map(value):
78 if value == "":
79 return []
80 return value.split(",")
82 return Hardware(cpus=args.cpus,
83 mem=args.mem,
85 src_cpu_bind=split_map(args.src_cpu_bind),
86 src_mem_bind=split_map(args.src_mem_bind),
87 dst_cpu_bind=split_map(args.dst_cpu_bind),
88 dst_mem_bind=split_map(args.dst_mem_bind),
90 locked_pages=args.locked_pages,
91 huge_pages=args.huge_pages,
92 prealloc_pages=args.prealloc_pages)
95 class Shell(BaseShell):
97 def __init__(self):
98 super(Shell, self).__init__()
100 parser = self._parser
102 parser.add_argument("--output", dest="output", default=None)
104 # Scenario args
105 parser.add_argument("--max-iters", dest="max_iters", default=30, type=int)
106 parser.add_argument("--max-time", dest="max_time", default=300, type=int)
107 parser.add_argument("--bandwidth", dest="bandwidth", default=125000, type=int)
108 parser.add_argument("--downtime", dest="downtime", default=500, type=int)
110 parser.add_argument("--pause", dest="pause", default=False, action="store_true")
111 parser.add_argument("--pause-iters", dest="pause_iters", default=5, type=int)
113 parser.add_argument("--post-copy", dest="post_copy", default=False, action="store_true")
114 parser.add_argument("--post-copy-iters", dest="post_copy_iters", default=5, type=int)
116 parser.add_argument("--auto-converge", dest="auto_converge", default=False, action="store_true")
117 parser.add_argument("--auto-converge-step", dest="auto_converge_step", default=10, type=int)
119 parser.add_argument("--compression-mt", dest="compression_mt", default=False, action="store_true")
120 parser.add_argument("--compression-mt-threads", dest="compression_mt_threads", default=1, type=int)
122 parser.add_argument("--compression-xbzrle", dest="compression_xbzrle", default=False, action="store_true")
123 parser.add_argument("--compression-xbzrle-cache", dest="compression_xbzrle_cache", default=10, type=int)
125 def get_scenario(self, args):
126 return Scenario(name="perfreport",
127 downtime=args.downtime,
128 bandwidth=args.bandwidth,
129 max_iters=args.max_iters,
130 max_time=args.max_time,
132 pause=args.pause,
133 pause_iters=args.pause_iters,
135 post_copy=args.post_copy,
136 post_copy_iters=args.post_copy_iters,
138 auto_converge=args.auto_converge,
139 auto_converge_step=args.auto_converge_step,
141 compression_mt=args.compression_mt,
142 compression_mt_threads=args.compression_mt_threads,
144 compression_xbzrle=args.compression_xbzrle,
145 compression_xbzrle_cache=args.compression_xbzrle_cache)
147 def run(self, argv):
148 args = self._parser.parse_args(argv)
149 logging.basicConfig(level=(logging.DEBUG if args.debug else
150 logging.INFO if args.verbose else
151 logging.WARN))
154 engine = self.get_engine(args)
155 hardware = self.get_hardware(args)
156 scenario = self.get_scenario(args)
158 try:
159 report = engine.run(hardware, scenario)
160 if args.output is None:
161 print(report.to_json())
162 else:
163 with open(args.output, "w") as fh:
164 print(report.to_json(), file=fh)
165 return 0
166 except Exception as e:
167 print("Error: %s" % str(e), file=sys.stderr)
168 if args.debug:
169 raise
170 return 1
173 class BatchShell(BaseShell):
175 def __init__(self):
176 super(BatchShell, self).__init__()
178 parser = self._parser
180 parser.add_argument("--filter", dest="filter", default="*")
181 parser.add_argument("--output", dest="output", default=os.getcwd())
183 def run(self, argv):
184 args = self._parser.parse_args(argv)
185 logging.basicConfig(level=(logging.DEBUG if args.debug else
186 logging.INFO if args.verbose else
187 logging.WARN))
190 engine = self.get_engine(args)
191 hardware = self.get_hardware(args)
193 try:
194 for comparison in COMPARISONS:
195 compdir = os.path.join(args.output, comparison._name)
196 for scenario in comparison._scenarios:
197 name = os.path.join(comparison._name, scenario._name)
198 if not fnmatch.fnmatch(name, args.filter):
199 if args.verbose:
200 print("Skipping %s" % name)
201 continue
203 if args.verbose:
204 print("Running %s" % name)
206 dirname = os.path.join(args.output, comparison._name)
207 filename = os.path.join(dirname, scenario._name + ".json")
208 if not os.path.exists(dirname):
209 os.makedirs(dirname)
210 report = engine.run(hardware, scenario)
211 with open(filename, "w") as fh:
212 print(report.to_json(), file=fh)
213 except Exception as e:
214 print("Error: %s" % str(e), file=sys.stderr)
215 if args.debug:
216 raise
219 class PlotShell(object):
221 def __init__(self):
222 super(PlotShell, self).__init__()
224 self._parser = argparse.ArgumentParser(description="Migration Test Tool")
226 self._parser.add_argument("--output", dest="output", default=None)
228 self._parser.add_argument("--debug", dest="debug", default=False, action="store_true")
229 self._parser.add_argument("--verbose", dest="verbose", default=False, action="store_true")
231 self._parser.add_argument("--migration-iters", dest="migration_iters", default=False, action="store_true")
232 self._parser.add_argument("--total-guest-cpu", dest="total_guest_cpu", default=False, action="store_true")
233 self._parser.add_argument("--split-guest-cpu", dest="split_guest_cpu", default=False, action="store_true")
234 self._parser.add_argument("--qemu-cpu", dest="qemu_cpu", default=False, action="store_true")
235 self._parser.add_argument("--vcpu-cpu", dest="vcpu_cpu", default=False, action="store_true")
237 self._parser.add_argument("reports", nargs='*')
239 def run(self, argv):
240 args = self._parser.parse_args(argv)
241 logging.basicConfig(level=(logging.DEBUG if args.debug else
242 logging.INFO if args.verbose else
243 logging.WARN))
246 if len(args.reports) == 0:
247 print("At least one report required", file=sys.stderr)
248 return 1
250 if not (args.qemu_cpu or
251 args.vcpu_cpu or
252 args.total_guest_cpu or
253 args.split_guest_cpu):
254 print("At least one chart type is required", file=sys.stderr)
255 return 1
257 reports = []
258 for report in args.reports:
259 reports.append(Report.from_json_file(report))
261 plot = Plot(reports,
262 args.migration_iters,
263 args.total_guest_cpu,
264 args.split_guest_cpu,
265 args.qemu_cpu,
266 args.vcpu_cpu)
268 plot.generate(args.output)