qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

shell.py (11166B)


      1 #
      2 # Migration test command line shell integration
      3 #
      4 # Copyright (c) 2016 Red Hat, Inc.
      5 #
      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.1 of the License, or (at your option) any later version.
     10 #
     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.
     15 #
     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/>.
     18 #
     19 
     20 
     21 import argparse
     22 import fnmatch
     23 import os
     24 import os.path
     25 import platform
     26 import sys
     27 import logging
     28 
     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
     35 
     36 
     37 class BaseShell(object):
     38 
     39     def __init__(self):
     40         parser = argparse.ArgumentParser(description="Migration Test Tool")
     41 
     42         # Test args
     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")
     51 
     52 
     53         # Hardware args
     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)
     63 
     64         self._parser = parser
     65 
     66     def get_engine(self, args):
     67         return Engine(binary=args.binary,
     68                       dst_host=args.dst_host,
     69                       kernel=args.kernel,
     70                       initrd=args.initrd,
     71                       transport=args.transport,
     72                       sleep=args.sleep,
     73                       debug=args.debug,
     74                       verbose=args.verbose)
     75 
     76     def get_hardware(self, args):
     77         def split_map(value):
     78             if value == "":
     79                 return []
     80             return value.split(",")
     81 
     82         return Hardware(cpus=args.cpus,
     83                         mem=args.mem,
     84 
     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),
     89 
     90                         locked_pages=args.locked_pages,
     91                         huge_pages=args.huge_pages,
     92                         prealloc_pages=args.prealloc_pages)
     93 
     94 
     95 class Shell(BaseShell):
     96 
     97     def __init__(self):
     98         super(Shell, self).__init__()
     99 
    100         parser = self._parser
    101 
    102         parser.add_argument("--output", dest="output", default=None)
    103 
    104         # Scenario args
    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)
    109 
    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)
    112 
    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)
    115 
    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)
    118 
    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)
    121 
    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)
    124 
    125         parser.add_argument("--multifd", dest="multifd", default=False,
    126                             action="store_true")
    127         parser.add_argument("--multifd-channels", dest="multifd_channels",
    128                             default=2, type=int)
    129 
    130     def get_scenario(self, args):
    131         return Scenario(name="perfreport",
    132                         downtime=args.downtime,
    133                         bandwidth=args.bandwidth,
    134                         max_iters=args.max_iters,
    135                         max_time=args.max_time,
    136 
    137                         pause=args.pause,
    138                         pause_iters=args.pause_iters,
    139 
    140                         post_copy=args.post_copy,
    141                         post_copy_iters=args.post_copy_iters,
    142 
    143                         auto_converge=args.auto_converge,
    144                         auto_converge_step=args.auto_converge_step,
    145 
    146                         compression_mt=args.compression_mt,
    147                         compression_mt_threads=args.compression_mt_threads,
    148 
    149                         compression_xbzrle=args.compression_xbzrle,
    150                         compression_xbzrle_cache=args.compression_xbzrle_cache,
    151 
    152                         multifd=args.multifd,
    153                         multifd_channels=args.multifd_channels)
    154 
    155     def run(self, argv):
    156         args = self._parser.parse_args(argv)
    157         logging.basicConfig(level=(logging.DEBUG if args.debug else
    158                                    logging.INFO if args.verbose else
    159                                    logging.WARN))
    160 
    161 
    162         engine = self.get_engine(args)
    163         hardware = self.get_hardware(args)
    164         scenario = self.get_scenario(args)
    165 
    166         try:
    167             report = engine.run(hardware, scenario)
    168             if args.output is None:
    169                 print(report.to_json())
    170             else:
    171                 with open(args.output, "w") as fh:
    172                     print(report.to_json(), file=fh)
    173             return 0
    174         except Exception as e:
    175             print("Error: %s" % str(e), file=sys.stderr)
    176             if args.debug:
    177                 raise
    178             return 1
    179 
    180 
    181 class BatchShell(BaseShell):
    182 
    183     def __init__(self):
    184         super(BatchShell, self).__init__()
    185 
    186         parser = self._parser
    187 
    188         parser.add_argument("--filter", dest="filter", default="*")
    189         parser.add_argument("--output", dest="output", default=os.getcwd())
    190 
    191     def run(self, argv):
    192         args = self._parser.parse_args(argv)
    193         logging.basicConfig(level=(logging.DEBUG if args.debug else
    194                                    logging.INFO if args.verbose else
    195                                    logging.WARN))
    196 
    197 
    198         engine = self.get_engine(args)
    199         hardware = self.get_hardware(args)
    200 
    201         try:
    202             for comparison in COMPARISONS:
    203                 compdir = os.path.join(args.output, comparison._name)
    204                 for scenario in comparison._scenarios:
    205                     name = os.path.join(comparison._name, scenario._name)
    206                     if not fnmatch.fnmatch(name, args.filter):
    207                         if args.verbose:
    208                             print("Skipping %s" % name)
    209                         continue
    210 
    211                     if args.verbose:
    212                         print("Running %s" % name)
    213 
    214                     dirname = os.path.join(args.output, comparison._name)
    215                     filename = os.path.join(dirname, scenario._name + ".json")
    216                     if not os.path.exists(dirname):
    217                         os.makedirs(dirname)
    218                     report = engine.run(hardware, scenario)
    219                     with open(filename, "w") as fh:
    220                         print(report.to_json(), file=fh)
    221         except Exception as e:
    222             print("Error: %s" % str(e), file=sys.stderr)
    223             if args.debug:
    224                 raise
    225 
    226 
    227 class PlotShell(object):
    228 
    229     def __init__(self):
    230         super(PlotShell, self).__init__()
    231 
    232         self._parser = argparse.ArgumentParser(description="Migration Test Tool")
    233 
    234         self._parser.add_argument("--output", dest="output", default=None)
    235 
    236         self._parser.add_argument("--debug", dest="debug", default=False, action="store_true")
    237         self._parser.add_argument("--verbose", dest="verbose", default=False, action="store_true")
    238 
    239         self._parser.add_argument("--migration-iters", dest="migration_iters", default=False, action="store_true")
    240         self._parser.add_argument("--total-guest-cpu", dest="total_guest_cpu", default=False, action="store_true")
    241         self._parser.add_argument("--split-guest-cpu", dest="split_guest_cpu", default=False, action="store_true")
    242         self._parser.add_argument("--qemu-cpu", dest="qemu_cpu", default=False, action="store_true")
    243         self._parser.add_argument("--vcpu-cpu", dest="vcpu_cpu", default=False, action="store_true")
    244 
    245         self._parser.add_argument("reports", nargs='*')
    246 
    247     def run(self, argv):
    248         args = self._parser.parse_args(argv)
    249         logging.basicConfig(level=(logging.DEBUG if args.debug else
    250                                    logging.INFO if args.verbose else
    251                                    logging.WARN))
    252 
    253 
    254         if len(args.reports) == 0:
    255             print("At least one report required", file=sys.stderr)
    256             return 1
    257 
    258         if not (args.qemu_cpu or
    259                 args.vcpu_cpu or
    260                 args.total_guest_cpu or
    261                 args.split_guest_cpu):
    262             print("At least one chart type is required", file=sys.stderr)
    263             return 1
    264 
    265         reports = []
    266         for report in args.reports:
    267             reports.append(Report.from_json_file(report))
    268 
    269         plot = Plot(reports,
    270                     args.migration_iters,
    271                     args.total_guest_cpu,
    272                     args.split_guest_cpu,
    273                     args.qemu_cpu,
    274                     args.vcpu_cpu)
    275 
    276         plot.generate(args.output)