| # Record/replay test that boots a Linux kernel |
| # |
| # Copyright (c) 2020 ISP RAS |
| # |
| # Author: |
| # Pavel Dovgalyuk <Pavel.Dovgaluk@ispras.ru> |
| # |
| # This work is licensed under the terms of the GNU GPL, version 2 or |
| # later. See the COPYING file in the top-level directory. |
| |
| import os |
| import logging |
| import time |
| import subprocess |
| |
| from qemu_test.linuxkernel import LinuxKernelTest |
| |
| class ReplayKernelBase(LinuxKernelTest): |
| """ |
| Boots a Linux kernel in record mode and checks that the console |
| is operational and the kernel command line is properly passed |
| from QEMU to the kernel. |
| Then replays the same scenario and verifies, that QEMU correctly |
| terminates. |
| """ |
| |
| timeout = 180 |
| REPLAY_KERNEL_COMMAND_LINE = 'printk.time=1 panic=-1 ' |
| |
| def run_vm(self, kernel_path, kernel_command_line, console_pattern, |
| record, shift, args, replay_path): |
| # icount requires TCG to be available |
| self.require_accelerator('tcg') |
| |
| logger = logging.getLogger('replay') |
| start_time = time.time() |
| vm = self.get_vm(name='recording' if record else 'replay') |
| vm.set_console() |
| if record: |
| logger.info('recording the execution...') |
| mode = 'record' |
| else: |
| logger.info('replaying the execution...') |
| mode = 'replay' |
| vm.add_args('-icount', 'shift=%s,rr=%s,rrfile=%s' % |
| (shift, mode, replay_path), |
| '-kernel', kernel_path, |
| '-append', kernel_command_line, |
| '-net', 'none', |
| '-no-reboot') |
| if args: |
| vm.add_args(*args) |
| vm.launch() |
| self.wait_for_console_pattern(console_pattern, vm) |
| if record: |
| vm.shutdown() |
| logger.info('finished the recording with log size %s bytes' |
| % os.path.getsize(replay_path)) |
| self.run_replay_dump(replay_path) |
| logger.info('successfully tested replay-dump.py') |
| else: |
| vm.wait() |
| logger.info('successfully finished the replay') |
| elapsed = time.time() - start_time |
| logger.info('elapsed time %.2f sec' % elapsed) |
| return elapsed |
| |
| def run_replay_dump(self, replay_path): |
| try: |
| subprocess.check_call(["./scripts/replay-dump.py", |
| "-f", replay_path], |
| stdout=subprocess.DEVNULL) |
| except subprocess.CalledProcessError: |
| self.fail('replay-dump.py failed') |
| |
| def run_rr(self, kernel_path, kernel_command_line, console_pattern, |
| shift=7, args=None): |
| replay_path = os.path.join(self.workdir, 'replay.bin') |
| t1 = self.run_vm(kernel_path, kernel_command_line, console_pattern, |
| True, shift, args, replay_path) |
| t2 = self.run_vm(kernel_path, kernel_command_line, console_pattern, |
| False, shift, args, replay_path) |
| logger = logging.getLogger('replay') |
| logger.info('replay overhead {:.2%}'.format(t2 / t1 - 1)) |