From c761d741bf7b696849d952ea0391e2f2fce01c5d Mon Sep 17 00:00:00 2001 From: Muminul Islam Date: Thu, 5 Mar 2026 21:02:38 -0800 Subject: [PATCH] tests: Refactor test_virtio_queue_affinity into reusable helper Extract virtio queue affinity test logic into a standalone _test_virtio_queue_affinity helper that accepts a Guest reference. The helper verifies the host has at least 4 CPUs, boots a VM with per-queue affinity on the cloud-init disk, and asserts each disk queue thread is pinned to the expected cores. Replace hardcoded kernel and cmdline arguments with default_cpus() and default_kernel_cmdline(). Update the test call site in common_parallel to use GuestFactory and delegate to the new helper, enabling reuse with different guest types. Signed-off-by: Muminul Islam --- cloud-hypervisor/tests/integration.rs | 108 +++++++++++++------------- 1 file changed, 56 insertions(+), 52 deletions(-) diff --git a/cloud-hypervisor/tests/integration.rs b/cloud-hypervisor/tests/integration.rs index dbb29b675..ddb4ea00a 100644 --- a/cloud-hypervisor/tests/integration.rs +++ b/cloud-hypervisor/tests/integration.rs @@ -2538,6 +2538,58 @@ fn _test_cpu_affinity(guest: &Guest) { handle_child_output(r, &output); } +fn _test_virtio_queue_affinity(guest: &Guest) { + // We need the host to have at least 4 CPUs if we want to be able + // to run this test. + let host_cpus_count = exec_host_command_output("nproc"); + assert!( + String::from_utf8_lossy(&host_cpus_count.stdout) + .trim() + .parse::() + .unwrap_or(0) + >= 4 + ); + + let mut child = GuestCommand::new(guest) + .default_cpus() + .default_memory() + .default_kernel_cmdline() + .args([ + "--disk", + format!( + "path={}", + guest.disk_config.disk(DiskType::OperatingSystem).unwrap() + ) + .as_str(), + format!( + "path={},num_queues=4,queue_affinity=[0@[0,2],1@[1,3],2@[1],3@[3]]", + guest.disk_config.disk(DiskType::CloudInit).unwrap() + ) + .as_str(), + ]) + .default_net() + .capture_output() + .spawn() + .unwrap(); + + let r = std::panic::catch_unwind(|| { + guest.wait_vm_boot().unwrap(); + let pid = child.id(); + let taskset_q0 = exec_host_command_output(format!("taskset -pc $(ps -T -p {pid} | grep disk1_q0 | xargs | cut -f 2 -d \" \") | cut -f 6 -d \" \"").as_str()); + assert_eq!(String::from_utf8_lossy(&taskset_q0.stdout).trim(), "0,2"); + let taskset_q1 = exec_host_command_output(format!("taskset -pc $(ps -T -p {pid} | grep disk1_q1 | xargs | cut -f 2 -d \" \") | cut -f 6 -d \" \"").as_str()); + assert_eq!(String::from_utf8_lossy(&taskset_q1.stdout).trim(), "1,3"); + let taskset_q2 = exec_host_command_output(format!("taskset -pc $(ps -T -p {pid} | grep disk1_q2 | xargs | cut -f 2 -d \" \") | cut -f 6 -d \" \"").as_str()); + assert_eq!(String::from_utf8_lossy(&taskset_q2.stdout).trim(), "1"); + let taskset_q3 = exec_host_command_output(format!("taskset -pc $(ps -T -p {pid} | grep disk1_q3 | xargs | cut -f 2 -d \" \") | cut -f 6 -d \" \"").as_str()); + assert_eq!(String::from_utf8_lossy(&taskset_q3.stdout).trim(), "3"); + }); + + kill_child(&mut child); + let output = child.wait_with_output().unwrap(); + handle_child_output(r, &output); +} + mod common_parallel { use std::cmp; use std::fs::{File, OpenOptions, copy}; @@ -2683,58 +2735,10 @@ mod common_parallel { #[test] fn test_virtio_queue_affinity() { let disk_config = UbuntuDiskConfig::new(JAMMY_IMAGE_NAME.to_string()); - let guest = Guest::new(Box::new(disk_config)); - - // We need the host to have at least 4 CPUs if we want to be able - // to run this test. - let host_cpus_count = exec_host_command_output("nproc"); - assert!( - String::from_utf8_lossy(&host_cpus_count.stdout) - .trim() - .parse::() - .unwrap_or(0) - >= 4 - ); - - let mut child = GuestCommand::new(&guest) - .args(["--cpus", "boot=4"]) - .default_memory() - .args(["--kernel", direct_kernel_boot_path().to_str().unwrap()]) - .args(["--cmdline", DIRECT_KERNEL_BOOT_CMDLINE]) - .args([ - "--disk", - format!( - "path={}", - guest.disk_config.disk(DiskType::OperatingSystem).unwrap() - ) - .as_str(), - format!( - "path={},num_queues=4,queue_affinity=[0@[0,2],1@[1,3],2@[1],3@[3]]", - guest.disk_config.disk(DiskType::CloudInit).unwrap() - ) - .as_str(), - ]) - .default_net() - .capture_output() - .spawn() - .unwrap(); - - let r = std::panic::catch_unwind(|| { - guest.wait_vm_boot().unwrap(); - let pid = child.id(); - let taskset_q0 = exec_host_command_output(format!("taskset -pc $(ps -T -p {pid} | grep disk1_q0 | xargs | cut -f 2 -d \" \") | cut -f 6 -d \" \"").as_str()); - assert_eq!(String::from_utf8_lossy(&taskset_q0.stdout).trim(), "0,2"); - let taskset_q1 = exec_host_command_output(format!("taskset -pc $(ps -T -p {pid} | grep disk1_q1 | xargs | cut -f 2 -d \" \") | cut -f 6 -d \" \"").as_str()); - assert_eq!(String::from_utf8_lossy(&taskset_q1.stdout).trim(), "1,3"); - let taskset_q2 = exec_host_command_output(format!("taskset -pc $(ps -T -p {pid} | grep disk1_q2 | xargs | cut -f 2 -d \" \") | cut -f 6 -d \" \"").as_str()); - assert_eq!(String::from_utf8_lossy(&taskset_q2.stdout).trim(), "1"); - let taskset_q3 = exec_host_command_output(format!("taskset -pc $(ps -T -p {pid} | grep disk1_q3 | xargs | cut -f 2 -d \" \") | cut -f 6 -d \" \"").as_str()); - assert_eq!(String::from_utf8_lossy(&taskset_q3.stdout).trim(), "3"); - }); - - kill_child(&mut child); - let output = child.wait_with_output().unwrap(); - handle_child_output(r, &output); + let guest = GuestFactory::new_regular_guest_factory() + .create_guest(Box::new(disk_config)) + .with_cpu(4); + _test_virtio_queue_affinity(&guest); } #[test]