xref: /qemu/tests/functional/replay_kernel.py (revision 1405d7e60d8c98a28b29885f70da4f2e4407fbc6)
1# Record/replay test that boots a Linux kernel
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
11import os
12import logging
13import time
14import subprocess
15
16from qemu_test.linuxkernel import LinuxKernelTest
17
18class ReplayKernelBase(LinuxKernelTest):
19    """
20    Boots a Linux kernel in record mode and checks that the console
21    is operational and the kernel command line is properly passed
22    from QEMU to the kernel.
23    Then replays the same scenario and verifies, that QEMU correctly
24    terminates.
25    """
26
27    timeout = 180
28    REPLAY_KERNEL_COMMAND_LINE = 'printk.time=1 panic=-1 '
29
30    def run_vm(self, kernel_path, kernel_command_line, console_pattern,
31               record, shift, args, replay_path):
32        # icount requires TCG to be available
33        self.require_accelerator('tcg')
34
35        logger = logging.getLogger('replay')
36        start_time = time.time()
37        vm = self.get_vm(name='recording' if record else 'replay')
38        vm.set_console()
39        if record:
40            logger.info('recording the execution...')
41            mode = 'record'
42        else:
43            logger.info('replaying the execution...')
44            mode = 'replay'
45        vm.add_args('-icount', 'shift=%s,rr=%s,rrfile=%s' %
46                    (shift, mode, replay_path),
47                    '-kernel', kernel_path,
48                    '-append', kernel_command_line,
49                    '-net', 'none',
50                    '-no-reboot')
51        if args:
52            vm.add_args(*args)
53        vm.launch()
54        self.wait_for_console_pattern(console_pattern, vm)
55        if record:
56            vm.shutdown()
57            logger.info('finished the recording with log size %s bytes'
58                        % os.path.getsize(replay_path))
59            self.run_replay_dump(replay_path)
60            logger.info('successfully tested replay-dump.py')
61        else:
62            vm.wait()
63            logger.info('successfully finished the replay')
64        elapsed = time.time() - start_time
65        logger.info('elapsed time %.2f sec' % elapsed)
66        return elapsed
67
68    def run_replay_dump(self, replay_path):
69        try:
70            subprocess.check_call(["./scripts/replay-dump.py",
71                                   "-f", replay_path],
72                                  stdout=subprocess.DEVNULL)
73        except subprocess.CalledProcessError:
74            self.fail('replay-dump.py failed')
75
76    def run_rr(self, kernel_path, kernel_command_line, console_pattern,
77               shift=7, args=None):
78        replay_path = os.path.join(self.workdir, 'replay.bin')
79        t1 = self.run_vm(kernel_path, kernel_command_line, console_pattern,
80                         True, shift, args, replay_path)
81        t2 = self.run_vm(kernel_path, kernel_command_line, console_pattern,
82                         False, shift, args, replay_path)
83        logger = logging.getLogger('replay')
84        logger.info('replay overhead {:.2%}'.format(t2 / t1 - 1))
85