xref: /openbmc/qemu/tests/avocado/replay_linux.py (revision 2eefd4fcec4b8fe41ceee2a8f00cdec1fe81b75c)
1bbbd9b6eSWillian Rampazzo# Record/replay test that boots a complete Linux system via a cloud image
2bbbd9b6eSWillian Rampazzo#
3bbbd9b6eSWillian Rampazzo# Copyright (c) 2020 ISP RAS
4bbbd9b6eSWillian Rampazzo#
5bbbd9b6eSWillian Rampazzo# Author:
6bbbd9b6eSWillian Rampazzo#  Pavel Dovgalyuk <Pavel.Dovgaluk@ispras.ru>
7bbbd9b6eSWillian Rampazzo#
8bbbd9b6eSWillian Rampazzo# This work is licensed under the terms of the GNU GPL, version 2 or
9bbbd9b6eSWillian Rampazzo# later.  See the COPYING file in the top-level directory.
10bbbd9b6eSWillian Rampazzo
11bbbd9b6eSWillian Rampazzoimport os
12bbbd9b6eSWillian Rampazzoimport logging
13bbbd9b6eSWillian Rampazzoimport time
14bbbd9b6eSWillian Rampazzo
15bbbd9b6eSWillian Rampazzofrom avocado import skipUnless
169b59af62SPavel Dovgalyukfrom avocado_qemu import BUILD_DIR
17bbbd9b6eSWillian Rampazzofrom avocado.utils import cloudinit
18bbbd9b6eSWillian Rampazzofrom avocado.utils import network
19bbbd9b6eSWillian Rampazzofrom avocado.utils import vmimage
20bbbd9b6eSWillian Rampazzofrom avocado.utils import datadrainer
21bbbd9b6eSWillian Rampazzofrom avocado.utils.path import find_command
22816d4201SThomas Huthfrom avocado_qemu.linuxtest import LinuxTest
23bbbd9b6eSWillian Rampazzo
24bbbd9b6eSWillian Rampazzoclass ReplayLinux(LinuxTest):
25bbbd9b6eSWillian Rampazzo    """
26bbbd9b6eSWillian Rampazzo    Boots a Linux system, checking for a successful initialization
27bbbd9b6eSWillian Rampazzo    """
28bbbd9b6eSWillian Rampazzo
29bbbd9b6eSWillian Rampazzo    timeout = 1800
30bbbd9b6eSWillian Rampazzo    chksum = None
31bbbd9b6eSWillian Rampazzo    hdd = 'ide-hd'
32bbbd9b6eSWillian Rampazzo    cd = 'ide-cd'
33bbbd9b6eSWillian Rampazzo    bus = 'ide'
34bbbd9b6eSWillian Rampazzo
35bbbd9b6eSWillian Rampazzo    def setUp(self):
36c9d27a0fSPavel Dovgalyuk        # LinuxTest does many replay-incompatible things, but includes
37c9d27a0fSPavel Dovgalyuk        # useful methods. Do not setup LinuxTest here and just
38c9d27a0fSPavel Dovgalyuk        # call some functions.
39c9d27a0fSPavel Dovgalyuk        super(LinuxTest, self).setUp()
40c9d27a0fSPavel Dovgalyuk        self._set_distro()
41bbbd9b6eSWillian Rampazzo        self.boot_path = self.download_boot()
42c9d27a0fSPavel Dovgalyuk        self.phone_server = cloudinit.PhoneHomeServer(('0.0.0.0', 0),
43c9d27a0fSPavel Dovgalyuk                                                      self.name)
44c9d27a0fSPavel Dovgalyuk        ssh_pubkey, self.ssh_key = self.set_up_existing_ssh_keys()
45c9d27a0fSPavel Dovgalyuk        self.cloudinit_path = self.prepare_cloudinit(ssh_pubkey)
46bbbd9b6eSWillian Rampazzo
47bbbd9b6eSWillian Rampazzo    def vm_add_disk(self, vm, path, id, device):
48bbbd9b6eSWillian Rampazzo        bus_string = ''
49bbbd9b6eSWillian Rampazzo        if self.bus:
50bbbd9b6eSWillian Rampazzo            bus_string = ',bus=%s.%d' % (self.bus, id,)
516f6b7153SAlex Bennée        vm.add_args('-drive', 'file=%s,snapshot=on,id=disk%s,if=none' % (path, id))
52bbbd9b6eSWillian Rampazzo        vm.add_args('-drive',
53bbbd9b6eSWillian Rampazzo            'driver=blkreplay,id=disk%s-rr,if=none,image=disk%s' % (id, id))
54bbbd9b6eSWillian Rampazzo        vm.add_args('-device',
55bbbd9b6eSWillian Rampazzo            '%s,drive=disk%s-rr%s' % (device, id, bus_string))
56bbbd9b6eSWillian Rampazzo
576f6b7153SAlex Bennée    def vm_add_cdrom(self, vm, path, id, device):
586f6b7153SAlex Bennée        vm.add_args('-drive', 'file=%s,id=disk%s,if=none,media=cdrom' % (path, id))
596f6b7153SAlex Bennée
60bbbd9b6eSWillian Rampazzo    def launch_and_wait(self, record, args, shift):
610fc389feSThomas Huth        self.require_netdev('user')
62bbbd9b6eSWillian Rampazzo        vm = self.get_vm()
63bbbd9b6eSWillian Rampazzo        vm.add_args('-smp', '1')
64bbbd9b6eSWillian Rampazzo        vm.add_args('-m', '1024')
65c9d27a0fSPavel Dovgalyuk        vm.add_args('-netdev', 'user,id=vnet,hostfwd=:127.0.0.1:0-:22',
66c9d27a0fSPavel Dovgalyuk                    '-device', 'virtio-net,netdev=vnet')
67c9d27a0fSPavel Dovgalyuk        vm.add_args('-object', 'filter-replay,id=replay,netdev=vnet')
68bbbd9b6eSWillian Rampazzo        if args:
69bbbd9b6eSWillian Rampazzo            vm.add_args(*args)
70bbbd9b6eSWillian Rampazzo        self.vm_add_disk(vm, self.boot_path, 0, self.hdd)
716f6b7153SAlex Bennée        self.vm_add_cdrom(vm, self.cloudinit_path, 1, self.cd)
72bbbd9b6eSWillian Rampazzo        logger = logging.getLogger('replay')
73bbbd9b6eSWillian Rampazzo        if record:
74bbbd9b6eSWillian Rampazzo            logger.info('recording the execution...')
75bbbd9b6eSWillian Rampazzo            mode = 'record'
76bbbd9b6eSWillian Rampazzo        else:
77bbbd9b6eSWillian Rampazzo            logger.info('replaying the execution...')
78bbbd9b6eSWillian Rampazzo            mode = 'replay'
79bbbd9b6eSWillian Rampazzo        replay_path = os.path.join(self.workdir, 'replay.bin')
80bbbd9b6eSWillian Rampazzo        vm.add_args('-icount', 'shift=%s,rr=%s,rrfile=%s' %
81bbbd9b6eSWillian Rampazzo                    (shift, mode, replay_path))
82bbbd9b6eSWillian Rampazzo
83bbbd9b6eSWillian Rampazzo        start_time = time.time()
84bbbd9b6eSWillian Rampazzo
85bbbd9b6eSWillian Rampazzo        vm.set_console()
86bbbd9b6eSWillian Rampazzo        vm.launch()
87bbbd9b6eSWillian Rampazzo        console_drainer = datadrainer.LineLogger(vm.console_socket.fileno(),
88bbbd9b6eSWillian Rampazzo                                    logger=self.log.getChild('console'),
89bbbd9b6eSWillian Rampazzo                                    stop_check=(lambda : not vm.is_running()))
90bbbd9b6eSWillian Rampazzo        console_drainer.start()
91bbbd9b6eSWillian Rampazzo        if record:
92c9d27a0fSPavel Dovgalyuk            while not self.phone_server.instance_phoned_back:
93c9d27a0fSPavel Dovgalyuk                self.phone_server.handle_request()
94bbbd9b6eSWillian Rampazzo            vm.shutdown()
95bbbd9b6eSWillian Rampazzo            logger.info('finished the recording with log size %s bytes'
96bbbd9b6eSWillian Rampazzo                % os.path.getsize(replay_path))
97*4926b6e6SNicholas Piggin            self.run_replay_dump(replay_path)
98*4926b6e6SNicholas Piggin            logger.info('successfully tested replay-dump.py')
99bbbd9b6eSWillian Rampazzo        else:
100bbbd9b6eSWillian Rampazzo            vm.event_wait('SHUTDOWN', self.timeout)
101b8211095SPavel Dovgalyuk            vm.wait()
1022d8508bbSAlex Bennée            logger.info('successfully finished the replay')
103bbbd9b6eSWillian Rampazzo        elapsed = time.time() - start_time
104bbbd9b6eSWillian Rampazzo        logger.info('elapsed time %.2f sec' % elapsed)
105bbbd9b6eSWillian Rampazzo        return elapsed
106bbbd9b6eSWillian Rampazzo
107bbbd9b6eSWillian Rampazzo    def run_rr(self, args=None, shift=7):
108bbbd9b6eSWillian Rampazzo        t1 = self.launch_and_wait(True, args, shift)
109bbbd9b6eSWillian Rampazzo        t2 = self.launch_and_wait(False, args, shift)
110bbbd9b6eSWillian Rampazzo        logger = logging.getLogger('replay')
111bbbd9b6eSWillian Rampazzo        logger.info('replay overhead {:.2%}'.format(t2 / t1 - 1))
112bbbd9b6eSWillian Rampazzo
113*4926b6e6SNicholas Piggin    def run_replay_dump(self, replay_path):
114*4926b6e6SNicholas Piggin        try:
115*4926b6e6SNicholas Piggin            subprocess.check_call(["./scripts/replay-dump.py",
116*4926b6e6SNicholas Piggin                                   "-f", replay_path],
117*4926b6e6SNicholas Piggin                                  stdout=subprocess.DEVNULL)
118*4926b6e6SNicholas Piggin        except subprocess.CalledProcessError:
119*4926b6e6SNicholas Piggin            self.fail('replay-dump.py failed')
120*4926b6e6SNicholas Piggin
121bbbd9b6eSWillian Rampazzo@skipUnless(os.getenv('AVOCADO_TIMEOUT_EXPECTED'), 'Test might timeout')
122bbbd9b6eSWillian Rampazzoclass ReplayLinuxX8664(ReplayLinux):
123bbbd9b6eSWillian Rampazzo    """
124bbbd9b6eSWillian Rampazzo    :avocado: tags=arch:x86_64
125bbbd9b6eSWillian Rampazzo    :avocado: tags=accel:tcg
126bbbd9b6eSWillian Rampazzo    """
127bbbd9b6eSWillian Rampazzo
128bbbd9b6eSWillian Rampazzo    chksum = 'e3c1b309d9203604922d6e255c2c5d098a309c2d46215d8fc026954f3c5c27a0'
129bbbd9b6eSWillian Rampazzo
130bbbd9b6eSWillian Rampazzo    def test_pc_i440fx(self):
131bbbd9b6eSWillian Rampazzo        """
132bbbd9b6eSWillian Rampazzo        :avocado: tags=machine:pc
133bbbd9b6eSWillian Rampazzo        """
134bbbd9b6eSWillian Rampazzo        self.run_rr(shift=1)
135bbbd9b6eSWillian Rampazzo
136bbbd9b6eSWillian Rampazzo    def test_pc_q35(self):
137bbbd9b6eSWillian Rampazzo        """
138bbbd9b6eSWillian Rampazzo        :avocado: tags=machine:q35
139bbbd9b6eSWillian Rampazzo        """
140bbbd9b6eSWillian Rampazzo        self.run_rr(shift=3)
1413cd1dce3SPavel Dovgalyuk
1423cd1dce3SPavel Dovgalyuk@skipUnless(os.getenv('AVOCADO_TIMEOUT_EXPECTED'), 'Test might timeout')
1433cd1dce3SPavel Dovgalyukclass ReplayLinuxX8664Virtio(ReplayLinux):
1443cd1dce3SPavel Dovgalyuk    """
1453cd1dce3SPavel Dovgalyuk    :avocado: tags=arch:x86_64
1463cd1dce3SPavel Dovgalyuk    :avocado: tags=virtio
1473cd1dce3SPavel Dovgalyuk    :avocado: tags=accel:tcg
1483cd1dce3SPavel Dovgalyuk    """
1493cd1dce3SPavel Dovgalyuk
1503cd1dce3SPavel Dovgalyuk    hdd = 'virtio-blk-pci'
1513cd1dce3SPavel Dovgalyuk    cd = 'virtio-blk-pci'
1523cd1dce3SPavel Dovgalyuk    bus = None
1533cd1dce3SPavel Dovgalyuk
1543cd1dce3SPavel Dovgalyuk    chksum = 'e3c1b309d9203604922d6e255c2c5d098a309c2d46215d8fc026954f3c5c27a0'
1553cd1dce3SPavel Dovgalyuk
1563cd1dce3SPavel Dovgalyuk    def test_pc_i440fx(self):
1573cd1dce3SPavel Dovgalyuk        """
1583cd1dce3SPavel Dovgalyuk        :avocado: tags=machine:pc
1593cd1dce3SPavel Dovgalyuk        """
1603cd1dce3SPavel Dovgalyuk        self.run_rr(shift=1)
1613cd1dce3SPavel Dovgalyuk
1623cd1dce3SPavel Dovgalyuk    def test_pc_q35(self):
1633cd1dce3SPavel Dovgalyuk        """
1643cd1dce3SPavel Dovgalyuk        :avocado: tags=machine:q35
1653cd1dce3SPavel Dovgalyuk        """
1663cd1dce3SPavel Dovgalyuk        self.run_rr(shift=3)
1679b59af62SPavel Dovgalyuk
1689b59af62SPavel Dovgalyuk@skipUnless(os.getenv('AVOCADO_TIMEOUT_EXPECTED'), 'Test might timeout')
1699b59af62SPavel Dovgalyukclass ReplayLinuxAarch64(ReplayLinux):
1709b59af62SPavel Dovgalyuk    """
1719b59af62SPavel Dovgalyuk    :avocado: tags=accel:tcg
1729b59af62SPavel Dovgalyuk    :avocado: tags=arch:aarch64
1739b59af62SPavel Dovgalyuk    :avocado: tags=machine:virt
1749b59af62SPavel Dovgalyuk    :avocado: tags=cpu:max
1759b59af62SPavel Dovgalyuk    """
1769b59af62SPavel Dovgalyuk
1779b59af62SPavel Dovgalyuk    chksum = '1e18d9c0cf734940c4b5d5ec592facaed2af0ad0329383d5639c997fdf16fe49'
1789b59af62SPavel Dovgalyuk
1799b59af62SPavel Dovgalyuk    hdd = 'virtio-blk-device'
1809b59af62SPavel Dovgalyuk    cd = 'virtio-blk-device'
1819b59af62SPavel Dovgalyuk    bus = None
1829b59af62SPavel Dovgalyuk
1839b59af62SPavel Dovgalyuk    def get_common_args(self):
1849b59af62SPavel Dovgalyuk        return ('-bios',
1859b59af62SPavel Dovgalyuk                os.path.join(BUILD_DIR, 'pc-bios', 'edk2-aarch64-code.fd'),
1869b59af62SPavel Dovgalyuk                "-cpu", "max,lpa2=off",
1879b59af62SPavel Dovgalyuk                '-device', 'virtio-rng-pci,rng=rng0',
1889b59af62SPavel Dovgalyuk                '-object', 'rng-builtin,id=rng0')
1899b59af62SPavel Dovgalyuk
1909b59af62SPavel Dovgalyuk    def test_virt_gicv2(self):
1919b59af62SPavel Dovgalyuk        """
1929b59af62SPavel Dovgalyuk        :avocado: tags=machine:gic-version=2
1939b59af62SPavel Dovgalyuk        """
1949b59af62SPavel Dovgalyuk
1959b59af62SPavel Dovgalyuk        self.run_rr(shift=3,
1969b59af62SPavel Dovgalyuk                    args=(*self.get_common_args(),
1979b59af62SPavel Dovgalyuk                          "-machine", "virt,gic-version=2"))
1989b59af62SPavel Dovgalyuk
1999b59af62SPavel Dovgalyuk    def test_virt_gicv3(self):
2009b59af62SPavel Dovgalyuk        """
2019b59af62SPavel Dovgalyuk        :avocado: tags=machine:gic-version=3
2029b59af62SPavel Dovgalyuk        """
2039b59af62SPavel Dovgalyuk
2049b59af62SPavel Dovgalyuk        self.run_rr(shift=3,
2059b59af62SPavel Dovgalyuk                    args=(*self.get_common_args(),
206c05a88c6SPavel Dovgalyuk                          "-machine", "virt,gic-version=3"))
207