1# Record/replay test that boots a complete Linux system via a cloud image 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 14 15from avocado import skipUnless 16from avocado.utils import cloudinit 17from avocado.utils import network 18from avocado.utils import vmimage 19from avocado.utils import datadrainer 20from avocado.utils.path import find_command 21from avocado_qemu import LinuxTest 22 23class ReplayLinux(LinuxTest): 24 """ 25 Boots a Linux system, checking for a successful initialization 26 """ 27 28 timeout = 1800 29 chksum = None 30 hdd = 'ide-hd' 31 cd = 'ide-cd' 32 bus = 'ide' 33 34 def setUp(self): 35 super(ReplayLinux, self).setUp() 36 self.boot_path = self.download_boot() 37 self.cloudinit_path = self.prepare_cloudinit() 38 39 def vm_add_disk(self, vm, path, id, device): 40 bus_string = '' 41 if self.bus: 42 bus_string = ',bus=%s.%d' % (self.bus, id,) 43 vm.add_args('-drive', 'file=%s,snapshot,id=disk%s,if=none' % (path, id)) 44 vm.add_args('-drive', 45 'driver=blkreplay,id=disk%s-rr,if=none,image=disk%s' % (id, id)) 46 vm.add_args('-device', 47 '%s,drive=disk%s-rr%s' % (device, id, bus_string)) 48 49 def launch_and_wait(self, record, args, shift): 50 vm = self.get_vm() 51 vm.add_args('-smp', '1') 52 vm.add_args('-m', '1024') 53 vm.add_args('-object', 'filter-replay,id=replay,netdev=hub0port0') 54 if args: 55 vm.add_args(*args) 56 self.vm_add_disk(vm, self.boot_path, 0, self.hdd) 57 self.vm_add_disk(vm, self.cloudinit_path, 1, self.cd) 58 logger = logging.getLogger('replay') 59 if record: 60 logger.info('recording the execution...') 61 mode = 'record' 62 else: 63 logger.info('replaying the execution...') 64 mode = 'replay' 65 replay_path = os.path.join(self.workdir, 'replay.bin') 66 vm.add_args('-icount', 'shift=%s,rr=%s,rrfile=%s' % 67 (shift, mode, replay_path)) 68 69 start_time = time.time() 70 71 vm.set_console() 72 vm.launch() 73 console_drainer = datadrainer.LineLogger(vm.console_socket.fileno(), 74 logger=self.log.getChild('console'), 75 stop_check=(lambda : not vm.is_running())) 76 console_drainer.start() 77 if record: 78 cloudinit.wait_for_phone_home(('0.0.0.0', self.phone_home_port), 79 self.name) 80 vm.shutdown() 81 logger.info('finished the recording with log size %s bytes' 82 % os.path.getsize(replay_path)) 83 else: 84 vm.event_wait('SHUTDOWN', self.timeout) 85 vm.shutdown(True) 86 logger.info('successfully fihished the replay') 87 elapsed = time.time() - start_time 88 logger.info('elapsed time %.2f sec' % elapsed) 89 return elapsed 90 91 def run_rr(self, args=None, shift=7): 92 t1 = self.launch_and_wait(True, args, shift) 93 t2 = self.launch_and_wait(False, args, shift) 94 logger = logging.getLogger('replay') 95 logger.info('replay overhead {:.2%}'.format(t2 / t1 - 1)) 96 97@skipUnless(os.getenv('AVOCADO_TIMEOUT_EXPECTED'), 'Test might timeout') 98class ReplayLinuxX8664(ReplayLinux): 99 """ 100 :avocado: tags=arch:x86_64 101 :avocado: tags=accel:tcg 102 """ 103 104 chksum = 'e3c1b309d9203604922d6e255c2c5d098a309c2d46215d8fc026954f3c5c27a0' 105 106 def test_pc_i440fx(self): 107 """ 108 :avocado: tags=machine:pc 109 """ 110 self.run_rr(shift=1) 111 112 def test_pc_q35(self): 113 """ 114 :avocado: tags=machine:q35 115 """ 116 self.run_rr(shift=3) 117