xref: /qemu/tests/functional/test_memlock.py (revision d82bb3f5dd5647e0f470b4189096aced1447b09f)
1*ec3a7a71SAlexandr Moshkov#!/usr/bin/env python3
2*ec3a7a71SAlexandr Moshkov#
3*ec3a7a71SAlexandr Moshkov# Functional test that check overcommit memlock options
4*ec3a7a71SAlexandr Moshkov#
5*ec3a7a71SAlexandr Moshkov# Copyright (c) Yandex Technologies LLC, 2025
6*ec3a7a71SAlexandr Moshkov#
7*ec3a7a71SAlexandr Moshkov# Author:
8*ec3a7a71SAlexandr Moshkov#  Alexandr Moshkov <dtalexundeer@yandex-team.ru>
9*ec3a7a71SAlexandr Moshkov#
10*ec3a7a71SAlexandr Moshkov# SPDX-License-Identifier: GPL-2.0-or-later
11*ec3a7a71SAlexandr Moshkov
12*ec3a7a71SAlexandr Moshkovimport re
13*ec3a7a71SAlexandr Moshkov
14*ec3a7a71SAlexandr Moshkovfrom typing import Dict
15*ec3a7a71SAlexandr Moshkov
16*ec3a7a71SAlexandr Moshkovfrom qemu_test import QemuSystemTest
17*ec3a7a71SAlexandr Moshkovfrom qemu_test import skipLockedMemoryTest
18*ec3a7a71SAlexandr Moshkov
19*ec3a7a71SAlexandr Moshkov
20*ec3a7a71SAlexandr MoshkovSTATUS_VALUE_PATTERN = re.compile(r'^(\w+):\s+(\d+) kB', re.MULTILINE)
21*ec3a7a71SAlexandr Moshkov
22*ec3a7a71SAlexandr Moshkov
23*ec3a7a71SAlexandr Moshkov@skipLockedMemoryTest(2_097_152)  # 2GB
24*ec3a7a71SAlexandr Moshkovclass MemlockTest(QemuSystemTest):
25*ec3a7a71SAlexandr Moshkov    """
26*ec3a7a71SAlexandr Moshkov    Runs a guest with memlock options.
27*ec3a7a71SAlexandr Moshkov    Then verify, that this options is working correctly
28*ec3a7a71SAlexandr Moshkov    by checking the status file of the QEMU process.
29*ec3a7a71SAlexandr Moshkov    """
30*ec3a7a71SAlexandr Moshkov
31*ec3a7a71SAlexandr Moshkov    def common_vm_setup_with_memlock(self, memlock):
32*ec3a7a71SAlexandr Moshkov        self.vm.add_args('-overcommit', f'mem-lock={memlock}')
33*ec3a7a71SAlexandr Moshkov        self.vm.launch()
34*ec3a7a71SAlexandr Moshkov
35*ec3a7a71SAlexandr Moshkov    def test_memlock_off(self):
36*ec3a7a71SAlexandr Moshkov        self.common_vm_setup_with_memlock('off')
37*ec3a7a71SAlexandr Moshkov
38*ec3a7a71SAlexandr Moshkov        status = self.get_process_status_values(self.vm.get_pid())
39*ec3a7a71SAlexandr Moshkov
40*ec3a7a71SAlexandr Moshkov        self.assertTrue(status['VmLck'] == 0)
41*ec3a7a71SAlexandr Moshkov
42*ec3a7a71SAlexandr Moshkov    def test_memlock_on(self):
43*ec3a7a71SAlexandr Moshkov        self.common_vm_setup_with_memlock('on')
44*ec3a7a71SAlexandr Moshkov
45*ec3a7a71SAlexandr Moshkov        status = self.get_process_status_values(self.vm.get_pid())
46*ec3a7a71SAlexandr Moshkov
47*ec3a7a71SAlexandr Moshkov        # VmLck > 0 kB and almost all memory is resident
48*ec3a7a71SAlexandr Moshkov        self.assertTrue(status['VmLck'] > 0)
49*ec3a7a71SAlexandr Moshkov        self.assertTrue(status['VmRSS'] >= status['VmSize'] * 0.70)
50*ec3a7a71SAlexandr Moshkov
51*ec3a7a71SAlexandr Moshkov    def test_memlock_onfault(self):
52*ec3a7a71SAlexandr Moshkov        self.common_vm_setup_with_memlock('on-fault')
53*ec3a7a71SAlexandr Moshkov
54*ec3a7a71SAlexandr Moshkov        status = self.get_process_status_values(self.vm.get_pid())
55*ec3a7a71SAlexandr Moshkov
56*ec3a7a71SAlexandr Moshkov        # VmLck > 0 kB and only few memory is resident
57*ec3a7a71SAlexandr Moshkov        self.assertTrue(status['VmLck'] > 0)
58*ec3a7a71SAlexandr Moshkov        self.assertTrue(status['VmRSS'] <= status['VmSize'] * 0.30)
59*ec3a7a71SAlexandr Moshkov
60*ec3a7a71SAlexandr Moshkov    def get_process_status_values(self, pid: int) -> Dict[str, int]:
61*ec3a7a71SAlexandr Moshkov        result = {}
62*ec3a7a71SAlexandr Moshkov        raw_status = self._get_raw_process_status(pid)
63*ec3a7a71SAlexandr Moshkov
64*ec3a7a71SAlexandr Moshkov        for line in raw_status.split('\n'):
65*ec3a7a71SAlexandr Moshkov            if m := STATUS_VALUE_PATTERN.match(line):
66*ec3a7a71SAlexandr Moshkov                result[m.group(1)] = int(m.group(2))
67*ec3a7a71SAlexandr Moshkov
68*ec3a7a71SAlexandr Moshkov        return result
69*ec3a7a71SAlexandr Moshkov
70*ec3a7a71SAlexandr Moshkov    def _get_raw_process_status(self, pid: int) -> str:
71*ec3a7a71SAlexandr Moshkov        try:
72*ec3a7a71SAlexandr Moshkov            with open(f'/proc/{pid}/status', 'r') as f:
73*ec3a7a71SAlexandr Moshkov                return f.read()
74*ec3a7a71SAlexandr Moshkov        except FileNotFoundError:
75*ec3a7a71SAlexandr Moshkov            self.skipTest("Can't open status file of the process")
76*ec3a7a71SAlexandr Moshkov
77*ec3a7a71SAlexandr Moshkov
78*ec3a7a71SAlexandr Moshkovif __name__ == '__main__':
79*ec3a7a71SAlexandr Moshkov    MemlockTest.main()
80