| # 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') | |
| start_time = time.time() | |
| vm = self.get_vm(name='recording' if record else 'replay') | |
| vm.set_console() | |
| if record: | |
| self.log.info('recording the execution...') | |
| mode = 'record' | |
| else: | |
| self.log.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() | |
| self.log.info('finished the recording with log size %s bytes' | |
| % os.path.getsize(replay_path)) | |
| self.run_replay_dump(replay_path) | |
| self.log.info('successfully tested replay-dump.py') | |
| else: | |
| vm.wait() | |
| self.log.info('successfully finished the replay') | |
| elapsed = time.time() - start_time | |
| self.log.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) | |
| self.log.info('replay overhead {:.2%}'.format(t2 / t1 - 1)) |