1 # Record/replay test that boots a complete Linux system via a cloud image
3 # Copyright (c) 2020 ISP RAS
6 # Pavel Dovgalyuk <Pavel.Dovgaluk@ispras.ru>
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.
15 from avocado
import skipUnless
16 from avocado_qemu
import BUILD_DIR
17 from avocado
.utils
import cloudinit
18 from avocado
.utils
import network
19 from avocado
.utils
import vmimage
20 from avocado
.utils
import datadrainer
21 from avocado
.utils
.path
import find_command
22 from avocado_qemu
.linuxtest
import LinuxTest
24 class ReplayLinux(LinuxTest
):
26 Boots a Linux system, checking for a successful initialization
36 # LinuxTest does many replay-incompatible things, but includes
37 # useful methods. Do not setup LinuxTest here and just
38 # call some functions.
39 super(LinuxTest
, self
).setUp()
41 self
.boot_path
= self
.download_boot()
42 self
.phone_server
= cloudinit
.PhoneHomeServer(('0.0.0.0', 0),
44 ssh_pubkey
, self
.ssh_key
= self
.set_up_existing_ssh_keys()
45 self
.cloudinit_path
= self
.prepare_cloudinit(ssh_pubkey
)
47 def vm_add_disk(self
, vm
, path
, id, device
):
50 bus_string
= ',bus=%s.%d' % (self
.bus
, id,)
51 vm
.add_args('-drive', 'file=%s,snapshot=on,id=disk%s,if=none' % (path
, id))
53 'driver=blkreplay,id=disk%s-rr,if=none,image=disk%s' % (id, id))
54 vm
.add_args('-device',
55 '%s,drive=disk%s-rr%s' % (device
, id, bus_string
))
57 def vm_add_cdrom(self
, vm
, path
, id, device
):
58 vm
.add_args('-drive', 'file=%s,id=disk%s,if=none,media=cdrom' % (path
, id))
60 def launch_and_wait(self
, record
, args
, shift
):
61 self
.require_netdev('user')
63 vm
.add_args('-smp', '1')
64 vm
.add_args('-m', '1024')
65 vm
.add_args('-netdev', 'user,id=vnet,hostfwd=:127.0.0.1:0-:22',
66 '-device', 'virtio-net,netdev=vnet')
67 vm
.add_args('-object', 'filter-replay,id=replay,netdev=vnet')
70 self
.vm_add_disk(vm
, self
.boot_path
, 0, self
.hdd
)
71 self
.vm_add_cdrom(vm
, self
.cloudinit_path
, 1, self
.cd
)
72 logger
= logging
.getLogger('replay')
74 logger
.info('recording the execution...')
77 logger
.info('replaying the execution...')
79 replay_path
= os
.path
.join(self
.workdir
, 'replay.bin')
80 vm
.add_args('-icount', 'shift=%s,rr=%s,rrfile=%s' %
81 (shift
, mode
, replay_path
))
83 start_time
= time
.time()
87 console_drainer
= datadrainer
.LineLogger(vm
.console_socket
.fileno(),
88 logger
=self
.log
.getChild('console'),
89 stop_check
=(lambda : not vm
.is_running()))
90 console_drainer
.start()
92 while not self
.phone_server
.instance_phoned_back
:
93 self
.phone_server
.handle_request()
95 logger
.info('finished the recording with log size %s bytes'
96 % os
.path
.getsize(replay_path
))
97 self
.run_replay_dump(replay_path
)
98 logger
.info('successfully tested replay-dump.py')
100 vm
.event_wait('SHUTDOWN', self
.timeout
)
102 logger
.info('successfully finished the replay')
103 elapsed
= time
.time() - start_time
104 logger
.info('elapsed time %.2f sec' % elapsed
)
107 def run_rr(self
, args
=None, shift
=7):
108 t1
= self
.launch_and_wait(True, args
, shift
)
109 t2
= self
.launch_and_wait(False, args
, shift
)
110 logger
= logging
.getLogger('replay')
111 logger
.info('replay overhead {:.2%}'.format(t2
/ t1
- 1))
113 def run_replay_dump(self
, replay_path
):
115 subprocess
.check_call(["./scripts/replay-dump.py",
117 stdout
=subprocess
.DEVNULL
)
118 except subprocess
.CalledProcessError
:
119 self
.fail('replay-dump.py failed')
121 @skipUnless(os
.getenv('AVOCADO_TIMEOUT_EXPECTED'), 'Test might timeout')
122 class ReplayLinuxX8664(ReplayLinux
):
124 :avocado: tags=arch:x86_64
125 :avocado: tags=accel:tcg
128 chksum
= 'e3c1b309d9203604922d6e255c2c5d098a309c2d46215d8fc026954f3c5c27a0'
130 def test_pc_i440fx(self
):
132 :avocado: tags=machine:pc
136 def test_pc_q35(self
):
138 :avocado: tags=machine:q35
142 @skipUnless(os
.getenv('AVOCADO_TIMEOUT_EXPECTED'), 'Test might timeout')
143 class ReplayLinuxX8664Virtio(ReplayLinux
):
145 :avocado: tags=arch:x86_64
146 :avocado: tags=virtio
147 :avocado: tags=accel:tcg
150 hdd
= 'virtio-blk-pci'
151 cd
= 'virtio-blk-pci'
154 chksum
= 'e3c1b309d9203604922d6e255c2c5d098a309c2d46215d8fc026954f3c5c27a0'
156 def test_pc_i440fx(self
):
158 :avocado: tags=machine:pc
162 def test_pc_q35(self
):
164 :avocado: tags=machine:q35
168 @skipUnless(os
.getenv('AVOCADO_TIMEOUT_EXPECTED'), 'Test might timeout')
169 class ReplayLinuxAarch64(ReplayLinux
):
171 :avocado: tags=accel:tcg
172 :avocado: tags=arch:aarch64
173 :avocado: tags=machine:virt
174 :avocado: tags=cpu:max
177 chksum
= '1e18d9c0cf734940c4b5d5ec592facaed2af0ad0329383d5639c997fdf16fe49'
179 hdd
= 'virtio-blk-device'
180 cd
= 'virtio-blk-device'
183 def get_common_args(self
):
185 os
.path
.join(BUILD_DIR
, 'pc-bios', 'edk2-aarch64-code.fd'),
186 "-cpu", "max,lpa2=off",
187 '-device', 'virtio-rng-pci,rng=rng0',
188 '-object', 'rng-builtin,id=rng0')
190 def test_virt_gicv2(self
):
192 :avocado: tags=machine:gic-version=2
196 args
=(*self
.get_common_args(),
197 "-machine", "virt,gic-version=2"))
199 def test_virt_gicv3(self
):
201 :avocado: tags=machine:gic-version=3
205 args
=(*self
.get_common_args(),
206 "-machine", "virt,gic-version=3"))