11456e906SDaniel P. Berrangé#!/usr/bin/env python3 21456e906SDaniel P. Berrangé# 31456e906SDaniel P. Berrangé# virtio-balloon tests 41456e906SDaniel P. Berrangé# 51456e906SDaniel P. Berrangé# This work is licensed under the terms of the GNU GPL, version 2 or 61456e906SDaniel P. Berrangé# later. See the COPYING file in the top-level directory. 71456e906SDaniel P. Berrangé 81456e906SDaniel P. Berrangéimport time 91456e906SDaniel P. Berrangé 101456e906SDaniel P. Berrangéfrom qemu_test import QemuSystemTest, Asset 111456e906SDaniel P. Berrangéfrom qemu_test import wait_for_console_pattern 121456e906SDaniel P. Berrangéfrom qemu_test import exec_command_and_wait_for_pattern 131456e906SDaniel P. Berrangé 141456e906SDaniel P. BerrangéUNSET_STATS_VALUE = 18446744073709551615 151456e906SDaniel P. Berrangé 161456e906SDaniel P. Berrangé 171456e906SDaniel P. Berrangéclass VirtioBalloonx86(QemuSystemTest): 181456e906SDaniel P. Berrangé 191456e906SDaniel P. Berrangé ASSET_KERNEL = Asset( 201456e906SDaniel P. Berrangé ('https://archives.fedoraproject.org/pub/archive/fedora/linux/releases' 211456e906SDaniel P. Berrangé '/31/Server/x86_64/os/images/pxeboot/vmlinuz'), 221456e906SDaniel P. Berrangé 'd4738d03dbbe083ca610d0821d0a8f1488bebbdccef54ce33e3adb35fda00129') 231456e906SDaniel P. Berrangé 241456e906SDaniel P. Berrangé ASSET_INITRD = Asset( 251456e906SDaniel P. Berrangé ('https://archives.fedoraproject.org/pub/archive/fedora/linux/releases' 261456e906SDaniel P. Berrangé '/31/Server/x86_64/os/images/pxeboot/initrd.img'), 271456e906SDaniel P. Berrangé '277cd6c7adf77c7e63d73bbb2cded8ef9e2d3a2f100000e92ff1f8396513cd8b') 281456e906SDaniel P. Berrangé 291456e906SDaniel P. Berrangé ASSET_DISKIMAGE = Asset( 301456e906SDaniel P. Berrangé ('https://archives.fedoraproject.org/pub/archive/fedora/linux/releases' 311456e906SDaniel P. Berrangé '/31/Cloud/x86_64/images/Fedora-Cloud-Base-31-1.9.x86_64.qcow2'), 321456e906SDaniel P. Berrangé 'e3c1b309d9203604922d6e255c2c5d098a309c2d46215d8fc026954f3c5c27a0') 331456e906SDaniel P. Berrangé 341456e906SDaniel P. Berrangé DEFAULT_KERNEL_PARAMS = ('root=/dev/vda1 console=ttyS0 net.ifnames=0 ' 3584272158SDaniel P. Berrangé 'rd.rescue quiet') 361456e906SDaniel P. Berrangé 371456e906SDaniel P. Berrangé def wait_for_console_pattern(self, success_message, vm=None): 381456e906SDaniel P. Berrangé wait_for_console_pattern( 391456e906SDaniel P. Berrangé self, 401456e906SDaniel P. Berrangé success_message, 411456e906SDaniel P. Berrangé failure_message="Kernel panic - not syncing", 421456e906SDaniel P. Berrangé vm=vm, 431456e906SDaniel P. Berrangé ) 441456e906SDaniel P. Berrangé 451456e906SDaniel P. Berrangé def mount_root(self): 461456e906SDaniel P. Berrangé self.wait_for_console_pattern('Entering emergency mode.') 471456e906SDaniel P. Berrangé prompt = '# ' 481456e906SDaniel P. Berrangé self.wait_for_console_pattern(prompt) 491456e906SDaniel P. Berrangé 5084272158SDaniel P. Berrangé # Synchronize on virtio-block driver creating the root device 5184272158SDaniel P. Berrangé exec_command_and_wait_for_pattern(self, 5284272158SDaniel P. Berrangé "while ! (dmesg -c | grep vda:) ; do sleep 1 ; done", 5384272158SDaniel P. Berrangé "vda1") 5484272158SDaniel P. Berrangé 551456e906SDaniel P. Berrangé exec_command_and_wait_for_pattern(self, 'mount /dev/vda1 /sysroot', 561456e906SDaniel P. Berrangé prompt) 571456e906SDaniel P. Berrangé exec_command_and_wait_for_pattern(self, 'chroot /sysroot', 581456e906SDaniel P. Berrangé prompt) 591456e906SDaniel P. Berrangé exec_command_and_wait_for_pattern(self, "modprobe virtio-balloon", 601456e906SDaniel P. Berrangé prompt) 611456e906SDaniel P. Berrangé 621456e906SDaniel P. Berrangé def assert_initial_stats(self): 631456e906SDaniel P. Berrangé ret = self.vm.qmp('qom-get', 641456e906SDaniel P. Berrangé {'path': '/machine/peripheral/balloon', 651456e906SDaniel P. Berrangé 'property': 'guest-stats'})['return'] 661456e906SDaniel P. Berrangé when = ret.get('last-update') 671456e906SDaniel P. Berrangé assert when == 0 681456e906SDaniel P. Berrangé stats = ret.get('stats') 691456e906SDaniel P. Berrangé for name, val in stats.items(): 701456e906SDaniel P. Berrangé assert val == UNSET_STATS_VALUE 711456e906SDaniel P. Berrangé 721456e906SDaniel P. Berrangé def assert_running_stats(self, then): 7384272158SDaniel P. Berrangé # We told the QEMU to refresh stats every 100ms, but 7484272158SDaniel P. Berrangé # there can be a delay between virtio-ballon driver 7584272158SDaniel P. Berrangé # being modprobed and seeing the first stats refresh 7684272158SDaniel P. Berrangé # Retry a few times for robustness under heavy load 7784272158SDaniel P. Berrangé retries = 10 7884272158SDaniel P. Berrangé when = 0 7984272158SDaniel P. Berrangé while when == 0 and retries: 801456e906SDaniel P. Berrangé ret = self.vm.qmp('qom-get', 811456e906SDaniel P. Berrangé {'path': '/machine/peripheral/balloon', 821456e906SDaniel P. Berrangé 'property': 'guest-stats'})['return'] 831456e906SDaniel P. Berrangé when = ret.get('last-update') 8484272158SDaniel P. Berrangé if when == 0: 8584272158SDaniel P. Berrangé retries = retries - 1 8684272158SDaniel P. Berrangé time.sleep(0.5) 8784272158SDaniel P. Berrangé 881456e906SDaniel P. Berrangé now = time.time() 891456e906SDaniel P. Berrangé 901456e906SDaniel P. Berrangé assert when > then and when < now 911456e906SDaniel P. Berrangé stats = ret.get('stats') 921456e906SDaniel P. Berrangé # Stat we expect this particular Kernel to have set 931456e906SDaniel P. Berrangé expectData = [ 941456e906SDaniel P. Berrangé "stat-available-memory", 951456e906SDaniel P. Berrangé "stat-disk-caches", 961456e906SDaniel P. Berrangé "stat-free-memory", 971456e906SDaniel P. Berrangé "stat-htlb-pgalloc", 981456e906SDaniel P. Berrangé "stat-htlb-pgfail", 991456e906SDaniel P. Berrangé "stat-major-faults", 1001456e906SDaniel P. Berrangé "stat-minor-faults", 1011456e906SDaniel P. Berrangé "stat-swap-in", 1021456e906SDaniel P. Berrangé "stat-swap-out", 1031456e906SDaniel P. Berrangé "stat-total-memory", 1041456e906SDaniel P. Berrangé ] 1051456e906SDaniel P. Berrangé for name, val in stats.items(): 1061456e906SDaniel P. Berrangé if name in expectData: 1071456e906SDaniel P. Berrangé assert val != UNSET_STATS_VALUE 1081456e906SDaniel P. Berrangé else: 1091456e906SDaniel P. Berrangé assert val == UNSET_STATS_VALUE 1101456e906SDaniel P. Berrangé 1111456e906SDaniel P. Berrangé def test_virtio_balloon_stats(self): 1121456e906SDaniel P. Berrangé self.set_machine('q35') 113*4dc11ee4SThomas Huth self.require_accelerator("kvm") 1141456e906SDaniel P. Berrangé kernel_path = self.ASSET_KERNEL.fetch() 1151456e906SDaniel P. Berrangé initrd_path = self.ASSET_INITRD.fetch() 1161456e906SDaniel P. Berrangé diskimage_path = self.ASSET_DISKIMAGE.fetch() 1171456e906SDaniel P. Berrangé 1181456e906SDaniel P. Berrangé self.vm.set_console() 1191456e906SDaniel P. Berrangé self.vm.add_args("-S") 1201456e906SDaniel P. Berrangé self.vm.add_args("-cpu", "max") 1211456e906SDaniel P. Berrangé self.vm.add_args("-m", "2G") 1221456e906SDaniel P. Berrangé # Slow down BIOS phase with boot menu, so that after a system 1231456e906SDaniel P. Berrangé # reset, we can reliably catch the clean stats again in BIOS 1241456e906SDaniel P. Berrangé # phase before the guest OS launches 1251456e906SDaniel P. Berrangé self.vm.add_args("-boot", "menu=on") 126*4dc11ee4SThomas Huth self.vm.add_args("-accel", "kvm") 1271456e906SDaniel P. Berrangé self.vm.add_args("-device", "virtio-balloon,id=balloon") 1281456e906SDaniel P. Berrangé self.vm.add_args('-drive', 1291456e906SDaniel P. Berrangé f'file={diskimage_path},if=none,id=drv0,snapshot=on') 1301456e906SDaniel P. Berrangé self.vm.add_args('-device', 'virtio-blk-pci,bus=pcie.0,' + 1311456e906SDaniel P. Berrangé 'drive=drv0,id=virtio-disk0,bootindex=1') 1321456e906SDaniel P. Berrangé 1331456e906SDaniel P. Berrangé self.vm.add_args( 1341456e906SDaniel P. Berrangé "-kernel", 1351456e906SDaniel P. Berrangé kernel_path, 1361456e906SDaniel P. Berrangé "-initrd", 1371456e906SDaniel P. Berrangé initrd_path, 1381456e906SDaniel P. Berrangé "-append", 1391456e906SDaniel P. Berrangé self.DEFAULT_KERNEL_PARAMS 1401456e906SDaniel P. Berrangé ) 1411456e906SDaniel P. Berrangé self.vm.launch() 1421456e906SDaniel P. Berrangé 1431456e906SDaniel P. Berrangé # Poll stats at 100ms 1441456e906SDaniel P. Berrangé self.vm.qmp('qom-set', 1451456e906SDaniel P. Berrangé {'path': '/machine/peripheral/balloon', 1461456e906SDaniel P. Berrangé 'property': 'guest-stats-polling-interval', 1471456e906SDaniel P. Berrangé 'value': 100 }) 1481456e906SDaniel P. Berrangé 1491456e906SDaniel P. Berrangé # We've not run any guest code yet, neither BIOS or guest, 1501456e906SDaniel P. Berrangé # so stats should be all default values 1511456e906SDaniel P. Berrangé self.assert_initial_stats() 1521456e906SDaniel P. Berrangé 1531456e906SDaniel P. Berrangé self.vm.qmp('cont') 1541456e906SDaniel P. Berrangé 1551456e906SDaniel P. Berrangé then = time.time() 1561456e906SDaniel P. Berrangé self.mount_root() 1571456e906SDaniel P. Berrangé self.assert_running_stats(then) 1581456e906SDaniel P. Berrangé 1591456e906SDaniel P. Berrangé # Race window between these two commands, where we 1601456e906SDaniel P. Berrangé # rely on '-boot menu=on' to (hopefully) ensure we're 1611456e906SDaniel P. Berrangé # still executing the BIOS when QEMU processes the 1621456e906SDaniel P. Berrangé # 'stop', and thus have not loaded the virtio-balloon 1631456e906SDaniel P. Berrangé # driver in the guest 1641456e906SDaniel P. Berrangé self.vm.qmp('system_reset') 1651456e906SDaniel P. Berrangé self.vm.qmp('stop') 1661456e906SDaniel P. Berrangé 1671456e906SDaniel P. Berrangé # If the above assumption held, we're in BIOS now and 1681456e906SDaniel P. Berrangé # stats should be all back at their default values 1691456e906SDaniel P. Berrangé self.assert_initial_stats() 1701456e906SDaniel P. Berrangé self.vm.qmp('cont') 1711456e906SDaniel P. Berrangé 1721456e906SDaniel P. Berrangé then = time.time() 1731456e906SDaniel P. Berrangé self.mount_root() 1741456e906SDaniel P. Berrangé self.assert_running_stats(then) 1751456e906SDaniel P. Berrangé 1761456e906SDaniel P. Berrangé 1771456e906SDaniel P. Berrangéif __name__ == '__main__': 1781456e906SDaniel P. Berrangé QemuSystemTest.main() 179