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/>.
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):
40 parser
= argparse
.ArgumentParser(description
="Migration Test Tool")
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")
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)
66 def get_engine(self
, args
):
67 return Engine(binary
=args
.binary
,
68 dst_host
=args
.dst_host
,
71 transport
=args
.transport
,
76 def get_hardware(self
, args
):
80 return value
.split(",")
82 return Hardware(cpus
=args
.cpus
,
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
):
98 super(Shell
, self
).__init
__()
100 parser
= self
._parser
102 parser
.add_argument("--output", dest
="output", default
=None)
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
,
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
)
148 args
= self
._parser
.parse_args(argv
)
149 logging
.basicConfig(level
=(logging
.DEBUG
if args
.debug
else
150 logging
.INFO
if args
.verbose
else
154 engine
= self
.get_engine(args
)
155 hardware
= self
.get_hardware(args
)
156 scenario
= self
.get_scenario(args
)
159 report
= engine
.run(hardware
, scenario
)
160 if args
.output
is None:
161 print(report
.to_json())
163 with
open(args
.output
, "w") as fh
:
164 print(report
.to_json(), file=fh
)
166 except Exception as e
:
167 print("Error: %s" % str(e
), file=sys
.stderr
)
173 class BatchShell(BaseShell
):
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())
184 args
= self
._parser
.parse_args(argv
)
185 logging
.basicConfig(level
=(logging
.DEBUG
if args
.debug
else
186 logging
.INFO
if args
.verbose
else
190 engine
= self
.get_engine(args
)
191 hardware
= self
.get_hardware(args
)
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):
200 print("Skipping %s" % name
)
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
):
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
)
219 class PlotShell(object):
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
='*')
240 args
= self
._parser
.parse_args(argv
)
241 logging
.basicConfig(level
=(logging
.DEBUG
if args
.debug
else
242 logging
.INFO
if args
.verbose
else
246 if len(args
.reports
) == 0:
247 print("At least one report required", file=sys
.stderr
)
250 if not (args
.qemu_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
)
258 for report
in args
.reports
:
259 reports
.append(Report
.from_json_file(report
))
262 args
.migration_iters
,
263 args
.total_guest_cpu
,
264 args
.split_guest_cpu
,
268 plot
.generate(args
.output
)