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