qemu

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

replay_linux.py (6216B)


      1 # Record/replay test that boots a complete Linux system via a cloud image
      2 #
      3 # Copyright (c) 2020 ISP RAS
      4 #
      5 # Author:
      6 #  Pavel Dovgalyuk <Pavel.Dovgaluk@ispras.ru>
      7 #
      8 # This work is licensed under the terms of the GNU GPL, version 2 or
      9 # later.  See the COPYING file in the top-level directory.
     10 
     11 import os
     12 import logging
     13 import time
     14 
     15 from avocado import skipUnless
     16 from avocado_qemu import BUILD_DIR
     17 from avocado.utils import cloudinit
     18 from avocado.utils import network
     19 from avocado.utils import vmimage
     20 from avocado.utils import datadrainer
     21 from avocado.utils.path import find_command
     22 from avocado_qemu import LinuxTest
     23 
     24 class ReplayLinux(LinuxTest):
     25     """
     26     Boots a Linux system, checking for a successful initialization
     27     """
     28 
     29     timeout = 1800
     30     chksum = None
     31     hdd = 'ide-hd'
     32     cd = 'ide-cd'
     33     bus = 'ide'
     34 
     35     def setUp(self):
     36         # LinuxTest does many replay-incompatible things, but includes
     37         # useful methods. Do not setup LinuxTest here and just
     38         # call some functions.
     39         super(LinuxTest, self).setUp()
     40         self._set_distro()
     41         self.boot_path = self.download_boot()
     42         self.phone_server = cloudinit.PhoneHomeServer(('0.0.0.0', 0),
     43                                                       self.name)
     44         ssh_pubkey, self.ssh_key = self.set_up_existing_ssh_keys()
     45         self.cloudinit_path = self.prepare_cloudinit(ssh_pubkey)
     46 
     47     def vm_add_disk(self, vm, path, id, device):
     48         bus_string = ''
     49         if self.bus:
     50             bus_string = ',bus=%s.%d' % (self.bus, id,)
     51         vm.add_args('-drive', 'file=%s,snapshot,id=disk%s,if=none' % (path, id))
     52         vm.add_args('-drive',
     53             'driver=blkreplay,id=disk%s-rr,if=none,image=disk%s' % (id, id))
     54         vm.add_args('-device',
     55             '%s,drive=disk%s-rr%s' % (device, id, bus_string))
     56 
     57     def launch_and_wait(self, record, args, shift):
     58         self.require_netdev('user')
     59         vm = self.get_vm()
     60         vm.add_args('-smp', '1')
     61         vm.add_args('-m', '1024')
     62         vm.add_args('-netdev', 'user,id=vnet,hostfwd=:127.0.0.1:0-:22',
     63                     '-device', 'virtio-net,netdev=vnet')
     64         vm.add_args('-object', 'filter-replay,id=replay,netdev=vnet')
     65         if args:
     66             vm.add_args(*args)
     67         self.vm_add_disk(vm, self.boot_path, 0, self.hdd)
     68         self.vm_add_disk(vm, self.cloudinit_path, 1, self.cd)
     69         logger = logging.getLogger('replay')
     70         if record:
     71             logger.info('recording the execution...')
     72             mode = 'record'
     73         else:
     74             logger.info('replaying the execution...')
     75             mode = 'replay'
     76         replay_path = os.path.join(self.workdir, 'replay.bin')
     77         vm.add_args('-icount', 'shift=%s,rr=%s,rrfile=%s' %
     78                     (shift, mode, replay_path))
     79 
     80         start_time = time.time()
     81 
     82         vm.set_console()
     83         vm.launch()
     84         console_drainer = datadrainer.LineLogger(vm.console_socket.fileno(),
     85                                     logger=self.log.getChild('console'),
     86                                     stop_check=(lambda : not vm.is_running()))
     87         console_drainer.start()
     88         if record:
     89             while not self.phone_server.instance_phoned_back:
     90                 self.phone_server.handle_request()
     91             vm.shutdown()
     92             logger.info('finished the recording with log size %s bytes'
     93                 % os.path.getsize(replay_path))
     94         else:
     95             vm.event_wait('SHUTDOWN', self.timeout)
     96             vm.shutdown(True)
     97             logger.info('successfully fihished the replay')
     98         elapsed = time.time() - start_time
     99         logger.info('elapsed time %.2f sec' % elapsed)
    100         return elapsed
    101 
    102     def run_rr(self, args=None, shift=7):
    103         t1 = self.launch_and_wait(True, args, shift)
    104         t2 = self.launch_and_wait(False, args, shift)
    105         logger = logging.getLogger('replay')
    106         logger.info('replay overhead {:.2%}'.format(t2 / t1 - 1))
    107 
    108 @skipUnless(os.getenv('AVOCADO_TIMEOUT_EXPECTED'), 'Test might timeout')
    109 class ReplayLinuxX8664(ReplayLinux):
    110     """
    111     :avocado: tags=arch:x86_64
    112     :avocado: tags=accel:tcg
    113     """
    114 
    115     chksum = 'e3c1b309d9203604922d6e255c2c5d098a309c2d46215d8fc026954f3c5c27a0'
    116 
    117     def test_pc_i440fx(self):
    118         """
    119         :avocado: tags=machine:pc
    120         """
    121         self.run_rr(shift=1)
    122 
    123     def test_pc_q35(self):
    124         """
    125         :avocado: tags=machine:q35
    126         """
    127         self.run_rr(shift=3)
    128 
    129 @skipUnless(os.getenv('AVOCADO_TIMEOUT_EXPECTED'), 'Test might timeout')
    130 class ReplayLinuxX8664Virtio(ReplayLinux):
    131     """
    132     :avocado: tags=arch:x86_64
    133     :avocado: tags=virtio
    134     :avocado: tags=accel:tcg
    135     """
    136 
    137     hdd = 'virtio-blk-pci'
    138     cd = 'virtio-blk-pci'
    139     bus = None
    140 
    141     chksum = 'e3c1b309d9203604922d6e255c2c5d098a309c2d46215d8fc026954f3c5c27a0'
    142 
    143     def test_pc_i440fx(self):
    144         """
    145         :avocado: tags=machine:pc
    146         """
    147         self.run_rr(shift=1)
    148 
    149     def test_pc_q35(self):
    150         """
    151         :avocado: tags=machine:q35
    152         """
    153         self.run_rr(shift=3)
    154 
    155 @skipUnless(os.getenv('AVOCADO_TIMEOUT_EXPECTED'), 'Test might timeout')
    156 class ReplayLinuxAarch64(ReplayLinux):
    157     """
    158     :avocado: tags=accel:tcg
    159     :avocado: tags=arch:aarch64
    160     :avocado: tags=machine:virt
    161     :avocado: tags=cpu:max
    162     """
    163 
    164     chksum = '1e18d9c0cf734940c4b5d5ec592facaed2af0ad0329383d5639c997fdf16fe49'
    165 
    166     hdd = 'virtio-blk-device'
    167     cd = 'virtio-blk-device'
    168     bus = None
    169 
    170     def get_common_args(self):
    171         return ('-bios',
    172                 os.path.join(BUILD_DIR, 'pc-bios', 'edk2-aarch64-code.fd'),
    173                 "-cpu", "max,lpa2=off",
    174                 '-device', 'virtio-rng-pci,rng=rng0',
    175                 '-object', 'rng-builtin,id=rng0')
    176 
    177     def test_virt_gicv2(self):
    178         """
    179         :avocado: tags=machine:gic-version=2
    180         """
    181 
    182         self.run_rr(shift=3,
    183                     args=(*self.get_common_args(),
    184                           "-machine", "virt,gic-version=2"))
    185 
    186     def test_virt_gicv3(self):
    187         """
    188         :avocado: tags=machine:gic-version=3
    189         """
    190 
    191         self.run_rr(shift=3,
    192                     args=(*self.get_common_args(),
    193                           "-machine", "virt,gic-version=3"))