From 190ca62ac5c86a658c008674f1ae612c553a473a Mon Sep 17 00:00:00 2001 From: mcasquer Date: Tue, 10 Oct 2023 09:25:08 +0200 Subject: [PATCH] numa_prealloc_threads: Runtime cpu-affinity handling Modifies existing numa preallocation threads case to also cover the cpu-affinity handling. That means setting new affinities, inside and outside from QEMU. Finally it checks that the QEMU main thread remains untouched. Signed-off-by: mcasquer --- qemu/tests/cfg/numa_prealloc_threads.cfg | 7 +- qemu/tests/numa_prealloc_threads.py | 102 ++++++++++++++++++----- 2 files changed, 87 insertions(+), 22 deletions(-) diff --git a/qemu/tests/cfg/numa_prealloc_threads.cfg b/qemu/tests/cfg/numa_prealloc_threads.cfg index 3264a3a05e..a6c12ae6ef 100644 --- a/qemu/tests/cfg/numa_prealloc_threads.cfg +++ b/qemu/tests/cfg/numa_prealloc_threads.cfg @@ -9,8 +9,8 @@ vm_thread_contexts = "tc1" smp_fixed = 8 vcpu_maxcpus = ${smp_fixed} - vm_thread_context_cpu-affinity = "1-7" not_preprocess = yes + first_cpu-affinity = "1-7" variants: - @default: qemu_sandbox = on @@ -18,3 +18,8 @@ sandbox_error_message = "Setting CPU affinity failed: Operation not permitted" - sandbox_off: qemu_sandbox = off + variants operation: + - @default: + second_cpu-affinity = "1-3" + - boot_cpu_affinity: + vm_thread_context_cpu-affinity = "1-7" diff --git a/qemu/tests/numa_prealloc_threads.py b/qemu/tests/numa_prealloc_threads.py index 079caa8686..5f019f3234 100644 --- a/qemu/tests/numa_prealloc_threads.py +++ b/qemu/tests/numa_prealloc_threads.py @@ -1,12 +1,44 @@ import re from avocado.utils import cpu + from virttest import env_process from virttest import error_context from virttest.qemu_monitor import QMPCmdError from avocado.utils import process +def check_affinity(affinity, cmd_taskset, stage, test): + """ + :param affinity: the cpu affinity + :param cmd_taskset: the taskset command + :param stage: the new or current affinity + :param test: QEMU test object + """ + output = process.getoutput(cmd_taskset) + actual_affinity = re.search("%s affinity list: (%s)" % (stage, affinity), + output).group(1) + if actual_affinity != affinity: + test.fail("Expect %s cpu affinity '%s', but get '%s'" + % (stage, affinity, actual_affinity)) + + +def convert_affinity(affinity): + """ + convert the cpu affinitys between list (ex: [1, 2, 3]) + and qemu-kvm command line style (ex: 1-3) + """ + if isinstance(affinity, str): + start, end = affinity.split('-') + output = list(range(int(start), int(end) + 1)) + elif isinstance(affinity, list): + if len(affinity) == 1: + output = str(affinity[0]) + else: + output = "%s-%s" % (affinity[0], affinity[-1]) + return output + + @error_context.context_aware def run(test, params, env): """ @@ -16,25 +48,32 @@ def run(test, params, env): 3) Check the affinity obtained from QEMU is correct 4) With sandbox enabled, try to change the cpu-affinity and handle the error + 5) Set externally a new CPU affinity + 6) Check QEMU main thread remains untouched :param test: QEMU test object :param params: Dictionary with the test parameters :param env: Dictionary with test environment """ - test.log.info("Check host CPUs number") + error_context.base_context("Check host CPUs number", test.log.info) host_cpus = int(cpu.online_count()) smp_fixed = params.get_numeric("smp_fixed") if host_cpus < smp_fixed: - test.cancel("The host only has %d CPUs, it needs at least %d!" % (host_cpus, smp_fixed)) + test.cancel("The host only has %d CPUs, it needs at least %d!" + % (host_cpus, smp_fixed)) params['not_preprocess'] = "no" + first_cpu_affinity = params.get("first_cpu-affinity") + second_cpu_affinity = params.get("second_cpu-affinity") + operation_type = params.get("operation") timeout = params.get_numeric("login_timeout", 1000) env_process.preprocess(test, params, env) vm = env.get_vm(params["main_vm"]) vm.verify_alive() vm.wait_for_login(timeout=timeout) + error_context.context("Obtain the thread ID", test.log.info) thread_context_device = vm.devices.get_by_params({"backend": "thread-context"})[0] thread_context_device_id = thread_context_device.get_param("id") error_msg = params.get("sandbox_error_message", "") @@ -43,27 +82,48 @@ def run(test, params, env): if not thread_id: test.fail("No thread-id setted.") - expected_cpu_affinity = thread_context_device.get_param("cpu-affinity") + error_context.context("Check the CPU affinity", test.log.info) + qemu_cpu_affinity = thread_context_device.get_param("cpu-affinity", "0") cpu_affinity = vm.monitor.qom_get(thread_context_device_id, "cpu-affinity") - affinity = str(cpu_affinity[0]) + "-" + str(cpu_affinity[-1]) - test.log.debug("The affinity: %s and the expected_cpu_affinity: %s" - % (affinity, expected_cpu_affinity)) - if expected_cpu_affinity != affinity: + affinity = convert_affinity(cpu_affinity) + test.log.debug("The affinity: %s and the qemu_cpu_affinity: %s" + % (affinity, qemu_cpu_affinity)) + if qemu_cpu_affinity != affinity: test.fail("Test and QEMU cpu-affinity does not match!") - cmd_taskset = "taskset -c -p " + str(thread_id) - output = process.getoutput(cmd_taskset) - if not re.search(affinity, output): - test.fail("The affinities %s and %s do not match!" - % (affinity, str(output))) + cmd_taskset = "taskset -c -p %s" % thread_id + check_affinity(affinity, cmd_taskset, "current", test) sandbox = params.get("qemu_sandbox", "on") - if sandbox == "on": - try: - # The command is expected to fail - vm.monitor.qom_set(thread_context_device_id, "cpu-affinity", cpu_affinity) - except QMPCmdError as e: - test.log.debug("The expected error message: %s and the output: %s" - % (error_msg, e.data)) - if not re.search(error_msg, str(e.data)): - test.fail("Can not get expected error message: %s" % error_msg) + + error_context.base_context("Setting cpu-affinity: %s" % first_cpu_affinity, + test.log.info) + try: + vm.monitor.qom_set(thread_context_device_id, + "cpu-affinity", + convert_affinity(first_cpu_affinity)) + except QMPCmdError as e: + if sandbox == "off": + test.fail("Set cpu-affinity '%s' failed as: %s" + % (first_cpu_affinity, str(e.data))) + if not re.search(error_msg, str(e.data)): + test.fail("Cannot get expected error message: %s" % error_msg) + test.log.debug("Get the expected error message: %s" % error_msg) + else: + if sandbox == "on": + test.fail("Set cpu-affinity should fail when sandbox=on") + affinity = first_cpu_affinity + check_affinity(affinity, cmd_taskset, "current", test) + + if operation_type != "boot_cpu_affinity": + error_context.base_context("Set externally a new CPU affinity", + test.log.info) + cmd_taskset = "taskset -c -p %s %s" % (second_cpu_affinity, + str(thread_id)) + error_context.context("Verify the new cpu-affinity", test.log.info) + check_affinity(second_cpu_affinity, cmd_taskset, "new", test) + + error_context.context("Checking QEMU main thread remains untouched", + test.log.info) + cmd_taskset = "taskset -c -p %s" % vm.get_pid() + check_affinity(qemu_cpu_affinity, cmd_taskset, "current", test)