xref: /qemu/tests/migration/guestperf/shell.py (revision 22b7cb2c)
1409437e1SDaniel P. Berrange#
2409437e1SDaniel P. Berrange# Migration test command line shell integration
3409437e1SDaniel P. Berrange#
4409437e1SDaniel P. Berrange# Copyright (c) 2016 Red Hat, Inc.
5409437e1SDaniel P. Berrange#
6409437e1SDaniel P. Berrange# This library is free software; you can redistribute it and/or
7409437e1SDaniel P. Berrange# modify it under the terms of the GNU Lesser General Public
8409437e1SDaniel P. Berrange# License as published by the Free Software Foundation; either
93a645d36SGan Qixin# version 2.1 of the License, or (at your option) any later version.
10409437e1SDaniel P. Berrange#
11409437e1SDaniel P. Berrange# This library is distributed in the hope that it will be useful,
12409437e1SDaniel P. Berrange# but WITHOUT ANY WARRANTY; without even the implied warranty of
13409437e1SDaniel P. Berrange# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14409437e1SDaniel P. Berrange# Lesser General Public License for more details.
15409437e1SDaniel P. Berrange#
16409437e1SDaniel P. Berrange# You should have received a copy of the GNU Lesser General Public
17409437e1SDaniel P. Berrange# License along with this library; if not, see <http://www.gnu.org/licenses/>.
18409437e1SDaniel P. Berrange#
19409437e1SDaniel P. Berrange
20409437e1SDaniel P. Berrange
210ea47d0fSStefan Hajnocziimport argparse
220ea47d0fSStefan Hajnocziimport fnmatch
23afb62496SEduardo Habkostimport os
24afb62496SEduardo Habkostimport os.path
250ea47d0fSStefan Hajnocziimport platform
26afb62496SEduardo Habkostimport sys
278af09b80SEduardo Habkostimport logging
28409437e1SDaniel P. Berrange
29409437e1SDaniel P. Berrangefrom guestperf.hardware import Hardware
30409437e1SDaniel P. Berrangefrom guestperf.engine import Engine
31409437e1SDaniel P. Berrangefrom guestperf.scenario import Scenario
32409437e1SDaniel P. Berrangefrom guestperf.comparison import COMPARISONS
33409437e1SDaniel P. Berrangefrom guestperf.plot import Plot
34409437e1SDaniel P. Berrangefrom guestperf.report import Report
35409437e1SDaniel P. Berrange
36409437e1SDaniel P. Berrange
37409437e1SDaniel P. Berrangeclass BaseShell(object):
38409437e1SDaniel P. Berrange
39409437e1SDaniel P. Berrange    def __init__(self):
40409437e1SDaniel P. Berrange        parser = argparse.ArgumentParser(description="Migration Test Tool")
41409437e1SDaniel P. Berrange
42409437e1SDaniel P. Berrange        # Test args
43409437e1SDaniel P. Berrange        parser.add_argument("--debug", dest="debug", default=False, action="store_true")
44409437e1SDaniel P. Berrange        parser.add_argument("--verbose", dest="verbose", default=False, action="store_true")
45409437e1SDaniel P. Berrange        parser.add_argument("--sleep", dest="sleep", default=15, type=int)
46409437e1SDaniel P. Berrange        parser.add_argument("--binary", dest="binary", default="/usr/bin/qemu-system-x86_64")
47409437e1SDaniel P. Berrange        parser.add_argument("--dst-host", dest="dst_host", default="localhost")
48409437e1SDaniel P. Berrange        parser.add_argument("--kernel", dest="kernel", default="/boot/vmlinuz-%s" % platform.release())
49409437e1SDaniel P. Berrange        parser.add_argument("--initrd", dest="initrd", default="tests/migration/initrd-stress.img")
50409437e1SDaniel P. Berrange        parser.add_argument("--transport", dest="transport", default="unix")
51409437e1SDaniel P. Berrange
52409437e1SDaniel P. Berrange
53409437e1SDaniel P. Berrange        # Hardware args
54409437e1SDaniel P. Berrange        parser.add_argument("--cpus", dest="cpus", default=1, type=int)
55409437e1SDaniel P. Berrange        parser.add_argument("--mem", dest="mem", default=1, type=int)
56409437e1SDaniel P. Berrange        parser.add_argument("--src-cpu-bind", dest="src_cpu_bind", default="")
57409437e1SDaniel P. Berrange        parser.add_argument("--src-mem-bind", dest="src_mem_bind", default="")
58409437e1SDaniel P. Berrange        parser.add_argument("--dst-cpu-bind", dest="dst_cpu_bind", default="")
59409437e1SDaniel P. Berrange        parser.add_argument("--dst-mem-bind", dest="dst_mem_bind", default="")
60409437e1SDaniel P. Berrange        parser.add_argument("--prealloc-pages", dest="prealloc_pages", default=False)
61409437e1SDaniel P. Berrange        parser.add_argument("--huge-pages", dest="huge_pages", default=False)
62409437e1SDaniel P. Berrange        parser.add_argument("--locked-pages", dest="locked_pages", default=False)
634cc563d4SHyman Huang        parser.add_argument("--dirty-ring-size", dest="dirty_ring_size",
644cc563d4SHyman Huang                            default=0, type=int)
65409437e1SDaniel P. Berrange
66409437e1SDaniel P. Berrange        self._parser = parser
67409437e1SDaniel P. Berrange
68409437e1SDaniel P. Berrange    def get_engine(self, args):
69409437e1SDaniel P. Berrange        return Engine(binary=args.binary,
70409437e1SDaniel P. Berrange                      dst_host=args.dst_host,
71409437e1SDaniel P. Berrange                      kernel=args.kernel,
72409437e1SDaniel P. Berrange                      initrd=args.initrd,
73409437e1SDaniel P. Berrange                      transport=args.transport,
74409437e1SDaniel P. Berrange                      sleep=args.sleep,
75409437e1SDaniel P. Berrange                      debug=args.debug,
76409437e1SDaniel P. Berrange                      verbose=args.verbose)
77409437e1SDaniel P. Berrange
78409437e1SDaniel P. Berrange    def get_hardware(self, args):
79409437e1SDaniel P. Berrange        def split_map(value):
80409437e1SDaniel P. Berrange            if value == "":
81409437e1SDaniel P. Berrange                return []
82409437e1SDaniel P. Berrange            return value.split(",")
83409437e1SDaniel P. Berrange
84409437e1SDaniel P. Berrange        return Hardware(cpus=args.cpus,
85409437e1SDaniel P. Berrange                        mem=args.mem,
86409437e1SDaniel P. Berrange
87409437e1SDaniel P. Berrange                        src_cpu_bind=split_map(args.src_cpu_bind),
88409437e1SDaniel P. Berrange                        src_mem_bind=split_map(args.src_mem_bind),
89409437e1SDaniel P. Berrange                        dst_cpu_bind=split_map(args.dst_cpu_bind),
90409437e1SDaniel P. Berrange                        dst_mem_bind=split_map(args.dst_mem_bind),
91409437e1SDaniel P. Berrange
92409437e1SDaniel P. Berrange                        locked_pages=args.locked_pages,
93409437e1SDaniel P. Berrange                        huge_pages=args.huge_pages,
944cc563d4SHyman Huang                        prealloc_pages=args.prealloc_pages,
954cc563d4SHyman Huang
964cc563d4SHyman Huang                        dirty_ring_size=args.dirty_ring_size)
97409437e1SDaniel P. Berrange
98409437e1SDaniel P. Berrange
99409437e1SDaniel P. Berrangeclass Shell(BaseShell):
100409437e1SDaniel P. Berrange
101409437e1SDaniel P. Berrange    def __init__(self):
102409437e1SDaniel P. Berrange        super(Shell, self).__init__()
103409437e1SDaniel P. Berrange
104409437e1SDaniel P. Berrange        parser = self._parser
105409437e1SDaniel P. Berrange
106409437e1SDaniel P. Berrange        parser.add_argument("--output", dest="output", default=None)
107409437e1SDaniel P. Berrange
108409437e1SDaniel P. Berrange        # Scenario args
109409437e1SDaniel P. Berrange        parser.add_argument("--max-iters", dest="max_iters", default=30, type=int)
110409437e1SDaniel P. Berrange        parser.add_argument("--max-time", dest="max_time", default=300, type=int)
111409437e1SDaniel P. Berrange        parser.add_argument("--bandwidth", dest="bandwidth", default=125000, type=int)
112409437e1SDaniel P. Berrange        parser.add_argument("--downtime", dest="downtime", default=500, type=int)
113409437e1SDaniel P. Berrange
114409437e1SDaniel P. Berrange        parser.add_argument("--pause", dest="pause", default=False, action="store_true")
115409437e1SDaniel P. Berrange        parser.add_argument("--pause-iters", dest="pause_iters", default=5, type=int)
116409437e1SDaniel P. Berrange
117409437e1SDaniel P. Berrange        parser.add_argument("--post-copy", dest="post_copy", default=False, action="store_true")
118409437e1SDaniel P. Berrange        parser.add_argument("--post-copy-iters", dest="post_copy_iters", default=5, type=int)
119409437e1SDaniel P. Berrange
120409437e1SDaniel P. Berrange        parser.add_argument("--auto-converge", dest="auto_converge", default=False, action="store_true")
121409437e1SDaniel P. Berrange        parser.add_argument("--auto-converge-step", dest="auto_converge_step", default=10, type=int)
122409437e1SDaniel P. Berrange
123409437e1SDaniel P. Berrange        parser.add_argument("--compression-mt", dest="compression_mt", default=False, action="store_true")
124409437e1SDaniel P. Berrange        parser.add_argument("--compression-mt-threads", dest="compression_mt_threads", default=1, type=int)
125409437e1SDaniel P. Berrange
126409437e1SDaniel P. Berrange        parser.add_argument("--compression-xbzrle", dest="compression_xbzrle", default=False, action="store_true")
127409437e1SDaniel P. Berrange        parser.add_argument("--compression-xbzrle-cache", dest="compression_xbzrle_cache", default=10, type=int)
128409437e1SDaniel P. Berrange
1291c3baa1aSHyman        parser.add_argument("--multifd", dest="multifd", default=False,
1301c3baa1aSHyman                            action="store_true")
1311c3baa1aSHyman        parser.add_argument("--multifd-channels", dest="multifd_channels",
1321c3baa1aSHyman                            default=2, type=int)
1331c3baa1aSHyman
134*22b7cb2cSHyman Huang        parser.add_argument("--dirty-limit", dest="dirty_limit", default=False,
135*22b7cb2cSHyman Huang                            action="store_true")
136*22b7cb2cSHyman Huang
137*22b7cb2cSHyman Huang        parser.add_argument("--x-vcpu-dirty-limit-period",
138*22b7cb2cSHyman Huang                            dest="x_vcpu_dirty_limit_period",
139*22b7cb2cSHyman Huang                            default=500, type=int)
140*22b7cb2cSHyman Huang
141*22b7cb2cSHyman Huang        parser.add_argument("--vcpu-dirty-limit",
142*22b7cb2cSHyman Huang                            dest="vcpu_dirty_limit",
143*22b7cb2cSHyman Huang                            default=1, type=int)
144*22b7cb2cSHyman Huang
145409437e1SDaniel P. Berrange    def get_scenario(self, args):
146409437e1SDaniel P. Berrange        return Scenario(name="perfreport",
147409437e1SDaniel P. Berrange                        downtime=args.downtime,
148409437e1SDaniel P. Berrange                        bandwidth=args.bandwidth,
149409437e1SDaniel P. Berrange                        max_iters=args.max_iters,
150409437e1SDaniel P. Berrange                        max_time=args.max_time,
151409437e1SDaniel P. Berrange
152409437e1SDaniel P. Berrange                        pause=args.pause,
153409437e1SDaniel P. Berrange                        pause_iters=args.pause_iters,
154409437e1SDaniel P. Berrange
155409437e1SDaniel P. Berrange                        post_copy=args.post_copy,
156409437e1SDaniel P. Berrange                        post_copy_iters=args.post_copy_iters,
157409437e1SDaniel P. Berrange
158409437e1SDaniel P. Berrange                        auto_converge=args.auto_converge,
159409437e1SDaniel P. Berrange                        auto_converge_step=args.auto_converge_step,
160409437e1SDaniel P. Berrange
161409437e1SDaniel P. Berrange                        compression_mt=args.compression_mt,
162409437e1SDaniel P. Berrange                        compression_mt_threads=args.compression_mt_threads,
163409437e1SDaniel P. Berrange
164409437e1SDaniel P. Berrange                        compression_xbzrle=args.compression_xbzrle,
1651c3baa1aSHyman                        compression_xbzrle_cache=args.compression_xbzrle_cache,
1661c3baa1aSHyman
1671c3baa1aSHyman                        multifd=args.multifd,
168*22b7cb2cSHyman Huang                        multifd_channels=args.multifd_channels,
169*22b7cb2cSHyman Huang
170*22b7cb2cSHyman Huang                        dirty_limit=args.dirty_limit,
171*22b7cb2cSHyman Huang                        x_vcpu_dirty_limit_period=\
172*22b7cb2cSHyman Huang                            args.x_vcpu_dirty_limit_period,
173*22b7cb2cSHyman Huang                        vcpu_dirty_limit=args.vcpu_dirty_limit)
174409437e1SDaniel P. Berrange
175409437e1SDaniel P. Berrange    def run(self, argv):
176409437e1SDaniel P. Berrange        args = self._parser.parse_args(argv)
1778af09b80SEduardo Habkost        logging.basicConfig(level=(logging.DEBUG if args.debug else
1788af09b80SEduardo Habkost                                   logging.INFO if args.verbose else
1798af09b80SEduardo Habkost                                   logging.WARN))
1808af09b80SEduardo Habkost
181409437e1SDaniel P. Berrange
182409437e1SDaniel P. Berrange        engine = self.get_engine(args)
183409437e1SDaniel P. Berrange        hardware = self.get_hardware(args)
184409437e1SDaniel P. Berrange        scenario = self.get_scenario(args)
185409437e1SDaniel P. Berrange
186409437e1SDaniel P. Berrange        try:
187409437e1SDaniel P. Berrange            report = engine.run(hardware, scenario)
188409437e1SDaniel P. Berrange            if args.output is None:
189f03868bdSEduardo Habkost                print(report.to_json())
190409437e1SDaniel P. Berrange            else:
191409437e1SDaniel P. Berrange                with open(args.output, "w") as fh:
192f03868bdSEduardo Habkost                    print(report.to_json(), file=fh)
193409437e1SDaniel P. Berrange            return 0
194409437e1SDaniel P. Berrange        except Exception as e:
195f03868bdSEduardo Habkost            print("Error: %s" % str(e), file=sys.stderr)
196409437e1SDaniel P. Berrange            if args.debug:
197409437e1SDaniel P. Berrange                raise
198409437e1SDaniel P. Berrange            return 1
199409437e1SDaniel P. Berrange
200409437e1SDaniel P. Berrange
201409437e1SDaniel P. Berrangeclass BatchShell(BaseShell):
202409437e1SDaniel P. Berrange
203409437e1SDaniel P. Berrange    def __init__(self):
204409437e1SDaniel P. Berrange        super(BatchShell, self).__init__()
205409437e1SDaniel P. Berrange
206409437e1SDaniel P. Berrange        parser = self._parser
207409437e1SDaniel P. Berrange
208409437e1SDaniel P. Berrange        parser.add_argument("--filter", dest="filter", default="*")
209409437e1SDaniel P. Berrange        parser.add_argument("--output", dest="output", default=os.getcwd())
210409437e1SDaniel P. Berrange
211409437e1SDaniel P. Berrange    def run(self, argv):
212409437e1SDaniel P. Berrange        args = self._parser.parse_args(argv)
2138af09b80SEduardo Habkost        logging.basicConfig(level=(logging.DEBUG if args.debug else
2148af09b80SEduardo Habkost                                   logging.INFO if args.verbose else
2158af09b80SEduardo Habkost                                   logging.WARN))
2168af09b80SEduardo Habkost
217409437e1SDaniel P. Berrange
218409437e1SDaniel P. Berrange        engine = self.get_engine(args)
219409437e1SDaniel P. Berrange        hardware = self.get_hardware(args)
220409437e1SDaniel P. Berrange
221409437e1SDaniel P. Berrange        try:
222409437e1SDaniel P. Berrange            for comparison in COMPARISONS:
223409437e1SDaniel P. Berrange                compdir = os.path.join(args.output, comparison._name)
224409437e1SDaniel P. Berrange                for scenario in comparison._scenarios:
225409437e1SDaniel P. Berrange                    name = os.path.join(comparison._name, scenario._name)
226409437e1SDaniel P. Berrange                    if not fnmatch.fnmatch(name, args.filter):
227409437e1SDaniel P. Berrange                        if args.verbose:
228f03868bdSEduardo Habkost                            print("Skipping %s" % name)
229409437e1SDaniel P. Berrange                        continue
230409437e1SDaniel P. Berrange
231409437e1SDaniel P. Berrange                    if args.verbose:
232f03868bdSEduardo Habkost                        print("Running %s" % name)
233409437e1SDaniel P. Berrange
234409437e1SDaniel P. Berrange                    dirname = os.path.join(args.output, comparison._name)
235409437e1SDaniel P. Berrange                    filename = os.path.join(dirname, scenario._name + ".json")
236409437e1SDaniel P. Berrange                    if not os.path.exists(dirname):
237409437e1SDaniel P. Berrange                        os.makedirs(dirname)
238409437e1SDaniel P. Berrange                    report = engine.run(hardware, scenario)
239409437e1SDaniel P. Berrange                    with open(filename, "w") as fh:
240f03868bdSEduardo Habkost                        print(report.to_json(), file=fh)
241409437e1SDaniel P. Berrange        except Exception as e:
242f03868bdSEduardo Habkost            print("Error: %s" % str(e), file=sys.stderr)
243409437e1SDaniel P. Berrange            if args.debug:
244409437e1SDaniel P. Berrange                raise
245409437e1SDaniel P. Berrange
246409437e1SDaniel P. Berrange
247409437e1SDaniel P. Berrangeclass PlotShell(object):
248409437e1SDaniel P. Berrange
249409437e1SDaniel P. Berrange    def __init__(self):
250409437e1SDaniel P. Berrange        super(PlotShell, self).__init__()
251409437e1SDaniel P. Berrange
252409437e1SDaniel P. Berrange        self._parser = argparse.ArgumentParser(description="Migration Test Tool")
253409437e1SDaniel P. Berrange
254409437e1SDaniel P. Berrange        self._parser.add_argument("--output", dest="output", default=None)
255409437e1SDaniel P. Berrange
256409437e1SDaniel P. Berrange        self._parser.add_argument("--debug", dest="debug", default=False, action="store_true")
257409437e1SDaniel P. Berrange        self._parser.add_argument("--verbose", dest="verbose", default=False, action="store_true")
258409437e1SDaniel P. Berrange
259409437e1SDaniel P. Berrange        self._parser.add_argument("--migration-iters", dest="migration_iters", default=False, action="store_true")
260409437e1SDaniel P. Berrange        self._parser.add_argument("--total-guest-cpu", dest="total_guest_cpu", default=False, action="store_true")
261409437e1SDaniel P. Berrange        self._parser.add_argument("--split-guest-cpu", dest="split_guest_cpu", default=False, action="store_true")
262409437e1SDaniel P. Berrange        self._parser.add_argument("--qemu-cpu", dest="qemu_cpu", default=False, action="store_true")
263409437e1SDaniel P. Berrange        self._parser.add_argument("--vcpu-cpu", dest="vcpu_cpu", default=False, action="store_true")
264409437e1SDaniel P. Berrange
265409437e1SDaniel P. Berrange        self._parser.add_argument("reports", nargs='*')
266409437e1SDaniel P. Berrange
267409437e1SDaniel P. Berrange    def run(self, argv):
268409437e1SDaniel P. Berrange        args = self._parser.parse_args(argv)
2698af09b80SEduardo Habkost        logging.basicConfig(level=(logging.DEBUG if args.debug else
2708af09b80SEduardo Habkost                                   logging.INFO if args.verbose else
2718af09b80SEduardo Habkost                                   logging.WARN))
2728af09b80SEduardo Habkost
273409437e1SDaniel P. Berrange
274409437e1SDaniel P. Berrange        if len(args.reports) == 0:
275f03868bdSEduardo Habkost            print("At least one report required", file=sys.stderr)
276409437e1SDaniel P. Berrange            return 1
277409437e1SDaniel P. Berrange
278409437e1SDaniel P. Berrange        if not (args.qemu_cpu or
279409437e1SDaniel P. Berrange                args.vcpu_cpu or
280409437e1SDaniel P. Berrange                args.total_guest_cpu or
281409437e1SDaniel P. Berrange                args.split_guest_cpu):
282f03868bdSEduardo Habkost            print("At least one chart type is required", file=sys.stderr)
283409437e1SDaniel P. Berrange            return 1
284409437e1SDaniel P. Berrange
285409437e1SDaniel P. Berrange        reports = []
286409437e1SDaniel P. Berrange        for report in args.reports:
287409437e1SDaniel P. Berrange            reports.append(Report.from_json_file(report))
288409437e1SDaniel P. Berrange
289409437e1SDaniel P. Berrange        plot = Plot(reports,
290409437e1SDaniel P. Berrange                    args.migration_iters,
291409437e1SDaniel P. Berrange                    args.total_guest_cpu,
292409437e1SDaniel P. Berrange                    args.split_guest_cpu,
293409437e1SDaniel P. Berrange                    args.qemu_cpu,
294409437e1SDaniel P. Berrange                    args.vcpu_cpu)
295409437e1SDaniel P. Berrange
296409437e1SDaniel P. Berrange        plot.generate(args.output)
297