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/>.
24 sys
.path
.append(os
.path
.join(os
.path
.dirname(__file__
),
25 '..', '..', '..', 'scripts'))
31 from guestperf
.hardware
import Hardware
32 from guestperf
.engine
import Engine
33 from guestperf
.scenario
import Scenario
34 from guestperf
.comparison
import COMPARISONS
35 from guestperf
.plot
import Plot
36 from guestperf
.report
import Report
39 class BaseShell(object):
42 parser
= argparse
.ArgumentParser(description
="Migration Test Tool")
45 parser
.add_argument("--debug", dest
="debug", default
=False, action
="store_true")
46 parser
.add_argument("--verbose", dest
="verbose", default
=False, action
="store_true")
47 parser
.add_argument("--sleep", dest
="sleep", default
=15, type=int)
48 parser
.add_argument("--binary", dest
="binary", default
="/usr/bin/qemu-system-x86_64")
49 parser
.add_argument("--dst-host", dest
="dst_host", default
="localhost")
50 parser
.add_argument("--kernel", dest
="kernel", default
="/boot/vmlinuz-%s" % platform
.release())
51 parser
.add_argument("--initrd", dest
="initrd", default
="tests/migration/initrd-stress.img")
52 parser
.add_argument("--transport", dest
="transport", default
="unix")
56 parser
.add_argument("--cpus", dest
="cpus", default
=1, type=int)
57 parser
.add_argument("--mem", dest
="mem", default
=1, type=int)
58 parser
.add_argument("--src-cpu-bind", dest
="src_cpu_bind", default
="")
59 parser
.add_argument("--src-mem-bind", dest
="src_mem_bind", default
="")
60 parser
.add_argument("--dst-cpu-bind", dest
="dst_cpu_bind", default
="")
61 parser
.add_argument("--dst-mem-bind", dest
="dst_mem_bind", default
="")
62 parser
.add_argument("--prealloc-pages", dest
="prealloc_pages", default
=False)
63 parser
.add_argument("--huge-pages", dest
="huge_pages", default
=False)
64 parser
.add_argument("--locked-pages", dest
="locked_pages", default
=False)
68 def get_engine(self
, args
):
69 return Engine(binary
=args
.binary
,
70 dst_host
=args
.dst_host
,
73 transport
=args
.transport
,
78 def get_hardware(self
, args
):
82 return value
.split(",")
84 return Hardware(cpus
=args
.cpus
,
87 src_cpu_bind
=split_map(args
.src_cpu_bind
),
88 src_mem_bind
=split_map(args
.src_mem_bind
),
89 dst_cpu_bind
=split_map(args
.dst_cpu_bind
),
90 dst_mem_bind
=split_map(args
.dst_mem_bind
),
92 locked_pages
=args
.locked_pages
,
93 huge_pages
=args
.huge_pages
,
94 prealloc_pages
=args
.prealloc_pages
)
97 class Shell(BaseShell
):
100 super(Shell
, self
).__init
__()
102 parser
= self
._parser
104 parser
.add_argument("--output", dest
="output", default
=None)
107 parser
.add_argument("--max-iters", dest
="max_iters", default
=30, type=int)
108 parser
.add_argument("--max-time", dest
="max_time", default
=300, type=int)
109 parser
.add_argument("--bandwidth", dest
="bandwidth", default
=125000, type=int)
110 parser
.add_argument("--downtime", dest
="downtime", default
=500, type=int)
112 parser
.add_argument("--pause", dest
="pause", default
=False, action
="store_true")
113 parser
.add_argument("--pause-iters", dest
="pause_iters", default
=5, type=int)
115 parser
.add_argument("--post-copy", dest
="post_copy", default
=False, action
="store_true")
116 parser
.add_argument("--post-copy-iters", dest
="post_copy_iters", default
=5, type=int)
118 parser
.add_argument("--auto-converge", dest
="auto_converge", default
=False, action
="store_true")
119 parser
.add_argument("--auto-converge-step", dest
="auto_converge_step", default
=10, type=int)
121 parser
.add_argument("--compression-mt", dest
="compression_mt", default
=False, action
="store_true")
122 parser
.add_argument("--compression-mt-threads", dest
="compression_mt_threads", default
=1, type=int)
124 parser
.add_argument("--compression-xbzrle", dest
="compression_xbzrle", default
=False, action
="store_true")
125 parser
.add_argument("--compression-xbzrle-cache", dest
="compression_xbzrle_cache", default
=10, type=int)
127 def get_scenario(self
, args
):
128 return Scenario(name
="perfreport",
129 downtime
=args
.downtime
,
130 bandwidth
=args
.bandwidth
,
131 max_iters
=args
.max_iters
,
132 max_time
=args
.max_time
,
135 pause_iters
=args
.pause_iters
,
137 post_copy
=args
.post_copy
,
138 post_copy_iters
=args
.post_copy_iters
,
140 auto_converge
=args
.auto_converge
,
141 auto_converge_step
=args
.auto_converge_step
,
143 compression_mt
=args
.compression_mt
,
144 compression_mt_threads
=args
.compression_mt_threads
,
146 compression_xbzrle
=args
.compression_xbzrle
,
147 compression_xbzrle_cache
=args
.compression_xbzrle_cache
)
150 args
= self
._parser
.parse_args(argv
)
151 logging
.basicConfig(level
=(logging
.DEBUG
if args
.debug
else
152 logging
.INFO
if args
.verbose
else
156 engine
= self
.get_engine(args
)
157 hardware
= self
.get_hardware(args
)
158 scenario
= self
.get_scenario(args
)
161 report
= engine
.run(hardware
, scenario
)
162 if args
.output
is None:
163 print report
.to_json()
165 with
open(args
.output
, "w") as fh
:
166 print >>fh
, report
.to_json()
168 except Exception as e
:
169 print >>sys
.stderr
, "Error: %s" % str(e
)
175 class BatchShell(BaseShell
):
178 super(BatchShell
, self
).__init
__()
180 parser
= self
._parser
182 parser
.add_argument("--filter", dest
="filter", default
="*")
183 parser
.add_argument("--output", dest
="output", default
=os
.getcwd())
186 args
= self
._parser
.parse_args(argv
)
187 logging
.basicConfig(level
=(logging
.DEBUG
if args
.debug
else
188 logging
.INFO
if args
.verbose
else
192 engine
= self
.get_engine(args
)
193 hardware
= self
.get_hardware(args
)
196 for comparison
in COMPARISONS
:
197 compdir
= os
.path
.join(args
.output
, comparison
._name
)
198 for scenario
in comparison
._scenarios
:
199 name
= os
.path
.join(comparison
._name
, scenario
._name
)
200 if not fnmatch
.fnmatch(name
, args
.filter):
202 print "Skipping %s" % name
206 print "Running %s" % name
208 dirname
= os
.path
.join(args
.output
, comparison
._name
)
209 filename
= os
.path
.join(dirname
, scenario
._name
+ ".json")
210 if not os
.path
.exists(dirname
):
212 report
= engine
.run(hardware
, scenario
)
213 with
open(filename
, "w") as fh
:
214 print >>fh
, report
.to_json()
215 except Exception as e
:
216 print >>sys
.stderr
, "Error: %s" % str(e
)
221 class PlotShell(object):
224 super(PlotShell
, self
).__init
__()
226 self
._parser
= argparse
.ArgumentParser(description
="Migration Test Tool")
228 self
._parser
.add_argument("--output", dest
="output", default
=None)
230 self
._parser
.add_argument("--debug", dest
="debug", default
=False, action
="store_true")
231 self
._parser
.add_argument("--verbose", dest
="verbose", default
=False, action
="store_true")
233 self
._parser
.add_argument("--migration-iters", dest
="migration_iters", default
=False, action
="store_true")
234 self
._parser
.add_argument("--total-guest-cpu", dest
="total_guest_cpu", default
=False, action
="store_true")
235 self
._parser
.add_argument("--split-guest-cpu", dest
="split_guest_cpu", default
=False, action
="store_true")
236 self
._parser
.add_argument("--qemu-cpu", dest
="qemu_cpu", default
=False, action
="store_true")
237 self
._parser
.add_argument("--vcpu-cpu", dest
="vcpu_cpu", default
=False, action
="store_true")
239 self
._parser
.add_argument("reports", nargs
='*')
242 args
= self
._parser
.parse_args(argv
)
243 logging
.basicConfig(level
=(logging
.DEBUG
if args
.debug
else
244 logging
.INFO
if args
.verbose
else
248 if len(args
.reports
) == 0:
249 print >>sys
.stderr
, "At least one report required"
252 if not (args
.qemu_cpu
or
254 args
.total_guest_cpu
or
255 args
.split_guest_cpu
):
256 print >>sys
.stderr
, "At least one chart type is required"
260 for report
in args
.reports
:
261 reports
.append(Report
.from_json_file(report
))
264 args
.migration_iters
,
265 args
.total_guest_cpu
,
266 args
.split_guest_cpu
,
270 plot
.generate(args
.output
)