xref: /openbmc/qemu/tests/migration-stress/guestperf/shell.py (revision 9af3d9a931156142199c61518937506bfa5475f1)
1212c1933SFabiano Rosas#
2212c1933SFabiano Rosas# Migration test command line shell integration
3212c1933SFabiano Rosas#
4212c1933SFabiano Rosas# Copyright (c) 2016 Red Hat, Inc.
5212c1933SFabiano Rosas#
6212c1933SFabiano Rosas# This library is free software; you can redistribute it and/or
7212c1933SFabiano Rosas# modify it under the terms of the GNU Lesser General Public
8212c1933SFabiano Rosas# License as published by the Free Software Foundation; either
9212c1933SFabiano Rosas# version 2.1 of the License, or (at your option) any later version.
10212c1933SFabiano Rosas#
11212c1933SFabiano Rosas# This library is distributed in the hope that it will be useful,
12212c1933SFabiano Rosas# but WITHOUT ANY WARRANTY; without even the implied warranty of
13212c1933SFabiano Rosas# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14212c1933SFabiano Rosas# Lesser General Public License for more details.
15212c1933SFabiano Rosas#
16212c1933SFabiano Rosas# You should have received a copy of the GNU Lesser General Public
17212c1933SFabiano Rosas# License along with this library; if not, see <http://www.gnu.org/licenses/>.
18212c1933SFabiano Rosas#
19212c1933SFabiano Rosas
20212c1933SFabiano Rosas
21212c1933SFabiano Rosasimport argparse
22212c1933SFabiano Rosasimport fnmatch
23212c1933SFabiano Rosasimport os
24212c1933SFabiano Rosasimport os.path
25212c1933SFabiano Rosasimport platform
26212c1933SFabiano Rosasimport sys
27212c1933SFabiano Rosasimport logging
28212c1933SFabiano Rosas
29212c1933SFabiano Rosasfrom guestperf.hardware import Hardware
30212c1933SFabiano Rosasfrom guestperf.engine import Engine
31212c1933SFabiano Rosasfrom guestperf.scenario import Scenario
32212c1933SFabiano Rosasfrom guestperf.comparison import COMPARISONS
33212c1933SFabiano Rosasfrom guestperf.plot import Plot
34212c1933SFabiano Rosasfrom guestperf.report import Report
35212c1933SFabiano Rosas
36212c1933SFabiano Rosas
37212c1933SFabiano Rosasclass BaseShell(object):
38212c1933SFabiano Rosas
39212c1933SFabiano Rosas    def __init__(self):
40212c1933SFabiano Rosas        parser = argparse.ArgumentParser(description="Migration Test Tool")
41212c1933SFabiano Rosas
42212c1933SFabiano Rosas        # Test args
43212c1933SFabiano Rosas        parser.add_argument("--debug", dest="debug", default=False, action="store_true")
44212c1933SFabiano Rosas        parser.add_argument("--verbose", dest="verbose", default=False, action="store_true")
45212c1933SFabiano Rosas        parser.add_argument("--sleep", dest="sleep", default=15, type=int)
46212c1933SFabiano Rosas        parser.add_argument("--binary", dest="binary", default="/usr/bin/qemu-system-x86_64")
47212c1933SFabiano Rosas        parser.add_argument("--dst-host", dest="dst_host", default="localhost")
48212c1933SFabiano Rosas        parser.add_argument("--kernel", dest="kernel", default="/boot/vmlinuz-%s" % platform.release())
49212c1933SFabiano Rosas        parser.add_argument("--initrd", dest="initrd",
50212c1933SFabiano Rosas                            default="tests/migration-stress/initrd-stress.img")
51212c1933SFabiano Rosas        parser.add_argument("--transport", dest="transport", default="unix")
52212c1933SFabiano Rosas
53212c1933SFabiano Rosas
54212c1933SFabiano Rosas        # Hardware args
55212c1933SFabiano Rosas        parser.add_argument("--cpus", dest="cpus", default=1, type=int)
56212c1933SFabiano Rosas        parser.add_argument("--mem", dest="mem", default=1, type=int)
57212c1933SFabiano Rosas        parser.add_argument("--src-cpu-bind", dest="src_cpu_bind", default="")
58212c1933SFabiano Rosas        parser.add_argument("--src-mem-bind", dest="src_mem_bind", default="")
59212c1933SFabiano Rosas        parser.add_argument("--dst-cpu-bind", dest="dst_cpu_bind", default="")
60212c1933SFabiano Rosas        parser.add_argument("--dst-mem-bind", dest="dst_mem_bind", default="")
61212c1933SFabiano Rosas        parser.add_argument("--prealloc-pages", dest="prealloc_pages", default=False)
62212c1933SFabiano Rosas        parser.add_argument("--huge-pages", dest="huge_pages", default=False)
63212c1933SFabiano Rosas        parser.add_argument("--locked-pages", dest="locked_pages", default=False)
64212c1933SFabiano Rosas        parser.add_argument("--dirty-ring-size", dest="dirty_ring_size",
65212c1933SFabiano Rosas                            default=0, type=int)
66212c1933SFabiano Rosas
67212c1933SFabiano Rosas        self._parser = parser
68212c1933SFabiano Rosas
69212c1933SFabiano Rosas    def get_engine(self, args):
70212c1933SFabiano Rosas        return Engine(binary=args.binary,
71212c1933SFabiano Rosas                      dst_host=args.dst_host,
72212c1933SFabiano Rosas                      kernel=args.kernel,
73212c1933SFabiano Rosas                      initrd=args.initrd,
74212c1933SFabiano Rosas                      transport=args.transport,
75212c1933SFabiano Rosas                      sleep=args.sleep,
76212c1933SFabiano Rosas                      debug=args.debug,
77212c1933SFabiano Rosas                      verbose=args.verbose)
78212c1933SFabiano Rosas
79212c1933SFabiano Rosas    def get_hardware(self, args):
80212c1933SFabiano Rosas        def split_map(value):
81212c1933SFabiano Rosas            if value == "":
82212c1933SFabiano Rosas                return []
83212c1933SFabiano Rosas            return value.split(",")
84212c1933SFabiano Rosas
85212c1933SFabiano Rosas        return Hardware(cpus=args.cpus,
86212c1933SFabiano Rosas                        mem=args.mem,
87212c1933SFabiano Rosas
88212c1933SFabiano Rosas                        src_cpu_bind=split_map(args.src_cpu_bind),
89212c1933SFabiano Rosas                        src_mem_bind=split_map(args.src_mem_bind),
90212c1933SFabiano Rosas                        dst_cpu_bind=split_map(args.dst_cpu_bind),
91212c1933SFabiano Rosas                        dst_mem_bind=split_map(args.dst_mem_bind),
92212c1933SFabiano Rosas
93212c1933SFabiano Rosas                        locked_pages=args.locked_pages,
94212c1933SFabiano Rosas                        huge_pages=args.huge_pages,
95212c1933SFabiano Rosas                        prealloc_pages=args.prealloc_pages,
96212c1933SFabiano Rosas
97212c1933SFabiano Rosas                        dirty_ring_size=args.dirty_ring_size)
98212c1933SFabiano Rosas
99212c1933SFabiano Rosas
100212c1933SFabiano Rosasclass Shell(BaseShell):
101212c1933SFabiano Rosas
102212c1933SFabiano Rosas    def __init__(self):
103212c1933SFabiano Rosas        super(Shell, self).__init__()
104212c1933SFabiano Rosas
105212c1933SFabiano Rosas        parser = self._parser
106212c1933SFabiano Rosas
107212c1933SFabiano Rosas        parser.add_argument("--output", dest="output", default=None)
108212c1933SFabiano Rosas
109212c1933SFabiano Rosas        # Scenario args
110212c1933SFabiano Rosas        parser.add_argument("--max-iters", dest="max_iters", default=30, type=int)
111212c1933SFabiano Rosas        parser.add_argument("--max-time", dest="max_time", default=300, type=int)
112212c1933SFabiano Rosas        parser.add_argument("--bandwidth", dest="bandwidth", default=125000, type=int)
113212c1933SFabiano Rosas        parser.add_argument("--downtime", dest="downtime", default=500, type=int)
114212c1933SFabiano Rosas
115212c1933SFabiano Rosas        parser.add_argument("--pause", dest="pause", default=False, action="store_true")
116212c1933SFabiano Rosas        parser.add_argument("--pause-iters", dest="pause_iters", default=5, type=int)
117212c1933SFabiano Rosas
118212c1933SFabiano Rosas        parser.add_argument("--post-copy", dest="post_copy", default=False, action="store_true")
119212c1933SFabiano Rosas        parser.add_argument("--post-copy-iters", dest="post_copy_iters", default=5, type=int)
120212c1933SFabiano Rosas
121212c1933SFabiano Rosas        parser.add_argument("--auto-converge", dest="auto_converge", default=False, action="store_true")
122212c1933SFabiano Rosas        parser.add_argument("--auto-converge-step", dest="auto_converge_step", default=10, type=int)
123212c1933SFabiano Rosas
124212c1933SFabiano Rosas        parser.add_argument("--compression-mt", dest="compression_mt", default=False, action="store_true")
125212c1933SFabiano Rosas        parser.add_argument("--compression-mt-threads", dest="compression_mt_threads", default=1, type=int)
126212c1933SFabiano Rosas
127212c1933SFabiano Rosas        parser.add_argument("--compression-xbzrle", dest="compression_xbzrle", default=False, action="store_true")
128212c1933SFabiano Rosas        parser.add_argument("--compression-xbzrle-cache", dest="compression_xbzrle_cache", default=10, type=int)
129212c1933SFabiano Rosas
130212c1933SFabiano Rosas        parser.add_argument("--multifd", dest="multifd", default=False,
131212c1933SFabiano Rosas                            action="store_true")
132212c1933SFabiano Rosas        parser.add_argument("--multifd-channels", dest="multifd_channels",
133212c1933SFabiano Rosas                            default=2, type=int)
134*45f34156SHyman Huang        parser.add_argument("--multifd-compression", dest="multifd_compression",
135*45f34156SHyman Huang                            default="")
136212c1933SFabiano Rosas
137212c1933SFabiano Rosas        parser.add_argument("--dirty-limit", dest="dirty_limit", default=False,
138212c1933SFabiano Rosas                            action="store_true")
139212c1933SFabiano Rosas
140212c1933SFabiano Rosas        parser.add_argument("--x-vcpu-dirty-limit-period",
141212c1933SFabiano Rosas                            dest="x_vcpu_dirty_limit_period",
142212c1933SFabiano Rosas                            default=500, type=int)
143212c1933SFabiano Rosas
144212c1933SFabiano Rosas        parser.add_argument("--vcpu-dirty-limit",
145212c1933SFabiano Rosas                            dest="vcpu_dirty_limit",
146212c1933SFabiano Rosas                            default=1, type=int)
147212c1933SFabiano Rosas
148212c1933SFabiano Rosas    def get_scenario(self, args):
149212c1933SFabiano Rosas        return Scenario(name="perfreport",
150212c1933SFabiano Rosas                        downtime=args.downtime,
151212c1933SFabiano Rosas                        bandwidth=args.bandwidth,
152212c1933SFabiano Rosas                        max_iters=args.max_iters,
153212c1933SFabiano Rosas                        max_time=args.max_time,
154212c1933SFabiano Rosas
155212c1933SFabiano Rosas                        pause=args.pause,
156212c1933SFabiano Rosas                        pause_iters=args.pause_iters,
157212c1933SFabiano Rosas
158212c1933SFabiano Rosas                        post_copy=args.post_copy,
159212c1933SFabiano Rosas                        post_copy_iters=args.post_copy_iters,
160212c1933SFabiano Rosas
161212c1933SFabiano Rosas                        auto_converge=args.auto_converge,
162212c1933SFabiano Rosas                        auto_converge_step=args.auto_converge_step,
163212c1933SFabiano Rosas
164212c1933SFabiano Rosas                        compression_mt=args.compression_mt,
165212c1933SFabiano Rosas                        compression_mt_threads=args.compression_mt_threads,
166212c1933SFabiano Rosas
167212c1933SFabiano Rosas                        compression_xbzrle=args.compression_xbzrle,
168212c1933SFabiano Rosas                        compression_xbzrle_cache=args.compression_xbzrle_cache,
169212c1933SFabiano Rosas
170212c1933SFabiano Rosas                        multifd=args.multifd,
171212c1933SFabiano Rosas                        multifd_channels=args.multifd_channels,
172*45f34156SHyman Huang                        multifd_compression=args.multifd_compression,
173212c1933SFabiano Rosas
174212c1933SFabiano Rosas                        dirty_limit=args.dirty_limit,
175212c1933SFabiano Rosas                        x_vcpu_dirty_limit_period=\
176212c1933SFabiano Rosas                            args.x_vcpu_dirty_limit_period,
177212c1933SFabiano Rosas                        vcpu_dirty_limit=args.vcpu_dirty_limit)
178212c1933SFabiano Rosas
179212c1933SFabiano Rosas    def run(self, argv):
180212c1933SFabiano Rosas        args = self._parser.parse_args(argv)
181212c1933SFabiano Rosas        logging.basicConfig(level=(logging.DEBUG if args.debug else
182212c1933SFabiano Rosas                                   logging.INFO if args.verbose else
183212c1933SFabiano Rosas                                   logging.WARN))
184212c1933SFabiano Rosas
185212c1933SFabiano Rosas
186212c1933SFabiano Rosas        engine = self.get_engine(args)
187212c1933SFabiano Rosas        hardware = self.get_hardware(args)
188212c1933SFabiano Rosas        scenario = self.get_scenario(args)
189212c1933SFabiano Rosas
190212c1933SFabiano Rosas        try:
191212c1933SFabiano Rosas            report = engine.run(hardware, scenario)
192212c1933SFabiano Rosas            if args.output is None:
193212c1933SFabiano Rosas                print(report.to_json())
194212c1933SFabiano Rosas            else:
195212c1933SFabiano Rosas                with open(args.output, "w") as fh:
196212c1933SFabiano Rosas                    print(report.to_json(), file=fh)
197212c1933SFabiano Rosas            return 0
198212c1933SFabiano Rosas        except Exception as e:
199212c1933SFabiano Rosas            print("Error: %s" % str(e), file=sys.stderr)
200212c1933SFabiano Rosas            if args.debug:
201212c1933SFabiano Rosas                raise
202212c1933SFabiano Rosas            return 1
203212c1933SFabiano Rosas
204212c1933SFabiano Rosas
205212c1933SFabiano Rosasclass BatchShell(BaseShell):
206212c1933SFabiano Rosas
207212c1933SFabiano Rosas    def __init__(self):
208212c1933SFabiano Rosas        super(BatchShell, self).__init__()
209212c1933SFabiano Rosas
210212c1933SFabiano Rosas        parser = self._parser
211212c1933SFabiano Rosas
212212c1933SFabiano Rosas        parser.add_argument("--filter", dest="filter", default="*")
213212c1933SFabiano Rosas        parser.add_argument("--output", dest="output", default=os.getcwd())
214212c1933SFabiano Rosas
215212c1933SFabiano Rosas    def run(self, argv):
216212c1933SFabiano Rosas        args = self._parser.parse_args(argv)
217212c1933SFabiano Rosas        logging.basicConfig(level=(logging.DEBUG if args.debug else
218212c1933SFabiano Rosas                                   logging.INFO if args.verbose else
219212c1933SFabiano Rosas                                   logging.WARN))
220212c1933SFabiano Rosas
221212c1933SFabiano Rosas
222212c1933SFabiano Rosas        engine = self.get_engine(args)
223212c1933SFabiano Rosas        hardware = self.get_hardware(args)
224212c1933SFabiano Rosas
225212c1933SFabiano Rosas        try:
226212c1933SFabiano Rosas            for comparison in COMPARISONS:
227212c1933SFabiano Rosas                compdir = os.path.join(args.output, comparison._name)
228212c1933SFabiano Rosas                for scenario in comparison._scenarios:
229212c1933SFabiano Rosas                    name = os.path.join(comparison._name, scenario._name)
230212c1933SFabiano Rosas                    if not fnmatch.fnmatch(name, args.filter):
231212c1933SFabiano Rosas                        if args.verbose:
232212c1933SFabiano Rosas                            print("Skipping %s" % name)
233212c1933SFabiano Rosas                        continue
234212c1933SFabiano Rosas
235212c1933SFabiano Rosas                    if args.verbose:
236212c1933SFabiano Rosas                        print("Running %s" % name)
237212c1933SFabiano Rosas
238212c1933SFabiano Rosas                    dirname = os.path.join(args.output, comparison._name)
239212c1933SFabiano Rosas                    filename = os.path.join(dirname, scenario._name + ".json")
240212c1933SFabiano Rosas                    if not os.path.exists(dirname):
241212c1933SFabiano Rosas                        os.makedirs(dirname)
242212c1933SFabiano Rosas                    report = engine.run(hardware, scenario)
243212c1933SFabiano Rosas                    with open(filename, "w") as fh:
244212c1933SFabiano Rosas                        print(report.to_json(), file=fh)
245212c1933SFabiano Rosas        except Exception as e:
246212c1933SFabiano Rosas            print("Error: %s" % str(e), file=sys.stderr)
247212c1933SFabiano Rosas            if args.debug:
248212c1933SFabiano Rosas                raise
249212c1933SFabiano Rosas
250212c1933SFabiano Rosas
251212c1933SFabiano Rosasclass PlotShell(object):
252212c1933SFabiano Rosas
253212c1933SFabiano Rosas    def __init__(self):
254212c1933SFabiano Rosas        super(PlotShell, self).__init__()
255212c1933SFabiano Rosas
256212c1933SFabiano Rosas        self._parser = argparse.ArgumentParser(description="Migration Test Tool")
257212c1933SFabiano Rosas
258212c1933SFabiano Rosas        self._parser.add_argument("--output", dest="output", default=None)
259212c1933SFabiano Rosas
260212c1933SFabiano Rosas        self._parser.add_argument("--debug", dest="debug", default=False, action="store_true")
261212c1933SFabiano Rosas        self._parser.add_argument("--verbose", dest="verbose", default=False, action="store_true")
262212c1933SFabiano Rosas
263212c1933SFabiano Rosas        self._parser.add_argument("--migration-iters", dest="migration_iters", default=False, action="store_true")
264212c1933SFabiano Rosas        self._parser.add_argument("--total-guest-cpu", dest="total_guest_cpu", default=False, action="store_true")
265212c1933SFabiano Rosas        self._parser.add_argument("--split-guest-cpu", dest="split_guest_cpu", default=False, action="store_true")
266212c1933SFabiano Rosas        self._parser.add_argument("--qemu-cpu", dest="qemu_cpu", default=False, action="store_true")
267212c1933SFabiano Rosas        self._parser.add_argument("--vcpu-cpu", dest="vcpu_cpu", default=False, action="store_true")
268212c1933SFabiano Rosas
269212c1933SFabiano Rosas        self._parser.add_argument("reports", nargs='*')
270212c1933SFabiano Rosas
271212c1933SFabiano Rosas    def run(self, argv):
272212c1933SFabiano Rosas        args = self._parser.parse_args(argv)
273212c1933SFabiano Rosas        logging.basicConfig(level=(logging.DEBUG if args.debug else
274212c1933SFabiano Rosas                                   logging.INFO if args.verbose else
275212c1933SFabiano Rosas                                   logging.WARN))
276212c1933SFabiano Rosas
277212c1933SFabiano Rosas
278212c1933SFabiano Rosas        if len(args.reports) == 0:
279212c1933SFabiano Rosas            print("At least one report required", file=sys.stderr)
280212c1933SFabiano Rosas            return 1
281212c1933SFabiano Rosas
282212c1933SFabiano Rosas        if not (args.qemu_cpu or
283212c1933SFabiano Rosas                args.vcpu_cpu or
284212c1933SFabiano Rosas                args.total_guest_cpu or
285212c1933SFabiano Rosas                args.split_guest_cpu):
286212c1933SFabiano Rosas            print("At least one chart type is required", file=sys.stderr)
287212c1933SFabiano Rosas            return 1
288212c1933SFabiano Rosas
289212c1933SFabiano Rosas        reports = []
290212c1933SFabiano Rosas        for report in args.reports:
291212c1933SFabiano Rosas            reports.append(Report.from_json_file(report))
292212c1933SFabiano Rosas
293212c1933SFabiano Rosas        plot = Plot(reports,
294212c1933SFabiano Rosas                    args.migration_iters,
295212c1933SFabiano Rosas                    args.total_guest_cpu,
296212c1933SFabiano Rosas                    args.split_guest_cpu,
297212c1933SFabiano Rosas                    args.qemu_cpu,
298212c1933SFabiano Rosas                    args.vcpu_cpu)
299212c1933SFabiano Rosas
300212c1933SFabiano Rosas        plot.generate(args.output)
301