xref: /openbmc/qemu/tests/functional/replay_kernel.py (revision 687a9b83833cda591a04f997a5260f85bd0c5e44)
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        start_time = time.time()
36        vm = self.get_vm(name='recording' if record else 'replay')
37        vm.set_console()
38        if record:
39            self.log.info('recording the execution...')
40            mode = 'record'
41        else:
42            self.log.info('replaying the execution...')
43            mode = 'replay'
44        vm.add_args('-icount', 'shift=%s,rr=%s,rrfile=%s' %
45                    (shift, mode, replay_path),
46                    '-kernel', kernel_path,
47                    '-append', kernel_command_line,
48                    '-net', 'none',
49                    '-no-reboot')
50        if args:
51            vm.add_args(*args)
52        vm.launch()
53        self.wait_for_console_pattern(console_pattern, vm)
54        if record:
55            vm.shutdown()
56            self.log.info('finished the recording with log size %s bytes'
57                        % os.path.getsize(replay_path))
58            self.run_replay_dump(replay_path)
59            self.log.info('successfully tested replay-dump.py')
60        else:
61            vm.wait()
62            self.log.info('successfully finished the replay')
63        elapsed = time.time() - start_time
64        self.log.info('elapsed time %.2f sec' % elapsed)
65        return elapsed
66
67    def run_replay_dump(self, replay_path):
68        try:
69            subprocess.check_call(["./scripts/replay-dump.py",
70                                   "-f", replay_path],
71                                  stdout=subprocess.DEVNULL)
72        except subprocess.CalledProcessError:
73            self.fail('replay-dump.py failed')
74
75    def run_rr(self, kernel_path, kernel_command_line, console_pattern,
76               shift=7, args=None):
77        replay_path = os.path.join(self.workdir, 'replay.bin')
78        t1 = self.run_vm(kernel_path, kernel_command_line, console_pattern,
79                         True, shift, args, replay_path)
80        t2 = self.run_vm(kernel_path, kernel_command_line, console_pattern,
81                         False, shift, args, replay_path)
82        self.log.info('replay overhead {:.2%}'.format(t2 / t1 - 1))
83