Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions libvirt/tests/cfg/libvirt_vcpu_plug_unplug.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,36 @@
vcpu_plug_num = 240
vcpu_unplug_num = 1
vcpu_max_num = 240
- multi_numa_hotplug:
only live
only libvirt_vcpu_plug_unplug
numa = "yes"
test_itr = 3
variants:
- numa_2_cells:
numa_cells = "2"
vcpu_max_num = "8"
vcpu_current_num = "2"
vcpu_plug_num = "6"
vcpu_unplug_num = "2"
smp = 8
vcpu_cores = 8
- numa_4_cells:
numa_cells = "4"
vcpu_max_num = "16"
vcpu_current_num = "4"
vcpu_plug_num = "12"
vcpu_unplug_num = "4"
smp = 16
vcpu_cores = 16
- numa_8_cells:
numa_cells = "8"
vcpu_max_num = "32"
vcpu_current_num = "8"
vcpu_plug_num = "24"
vcpu_unplug_num = "8"
smp = 32
vcpu_cores = 32

variants:
- live:
Expand Down
67 changes: 65 additions & 2 deletions libvirt/tests/src/libvirt_vcpu_plug_unplug.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import time

from avocado.utils import cpu as cpu_util
from virttest.libvirt_xml.vm_xml import VMCPUXML

from virttest import virsh
from virttest import data_dir
Expand Down Expand Up @@ -240,6 +241,7 @@ def check_setvcpus_result(cmd_result, expect_error):
with_stress = "yes" == params.get("run_stress", "no")
iterations = int(params.get("test_itr", 1))
topology_correction = "yes" == params.get("topology_correction", "no")
numa_cells_param = params.get("numa_cells")
# Init expect vcpu count values
expect_vcpu_num = {'max_config': vcpu_max_num, 'max_live': vcpu_max_num,
'cur_config': vcpu_current_num,
Expand Down Expand Up @@ -300,8 +302,69 @@ def check_setvcpus_result(cmd_result, expect_error):
vmxml.remove_agent_channels()
vmxml.sync()

vmxml.set_vm_vcpus(vm_name, vcpu_max_num, vcpu_current_num,
topology_correction=topology_correction)
if numa_cells_param:
# Configure multiple NUMA cells with evenly distributed CPUs/memory.
# Each cell gets (vcpu_max_num // numa_cells) CPUs and an equal
# share of the total guest memory (mem param, in MiB).
numa_cells = int(numa_cells_param)
logging.info("Configuring %d NUMA cells for multi-NUMA test",
numa_cells)

vmxml.vcpu = vcpu_max_num
vmxml.current_vcpu = vcpu_current_num

try:
cpu_xml = vmxml.cpu
except Exception:
cpu_xml = VMCPUXML()

# Ensure topology matches vcpu_max_num (sockets=1, cores=max, threads=1)
existing_topology = getattr(cpu_xml, 'topology', None)
topo_ok = False
if existing_topology:
topo_total = (int(existing_topology.get('sockets', 1)) *
int(existing_topology.get('cores', 1)) *
int(existing_topology.get('threads', 1)))
topo_ok = (topo_total == vcpu_max_num)
if not topo_ok:
cpu_xml.topology = {'sockets': 1,
'cores': vcpu_max_num,
'threads': 1}
logging.info("Set topology: sockets=1, cores=%d, threads=1",
vcpu_max_num)

# Build NUMA cell list — CPUs and memory split equally
cpus_per_cell = vcpu_max_num // numa_cells
remaining = vcpu_max_num % numa_cells
total_mem_mib = int(params.get("mem", "16384"))
cell_memory_kib = (total_mem_mib * 1024) // numa_cells

numa_cell_list = []
cpu_start = 0
for i in range(numa_cells):
cell_cpus = cpus_per_cell + (1 if i < remaining else 0)
cpu_end = cpu_start + cell_cpus - 1
cell_dict = {
'id': str(i),
'cpus': ("%d-%d" % (cpu_start, cpu_end)
if cell_cpus > 1 else str(cpu_start)),
'memory': str(cell_memory_kib),
'unit': 'KiB',
}
numa_cell_list.append(cell_dict)
logging.info("NUMA cell %d: CPUs %s, Memory %d KiB",
i, cell_dict['cpus'], cell_memory_kib)
cpu_start = cpu_end + 1

cpu_xml.numa_cell = cpu_xml.dicts_to_cells(numa_cell_list)
vmxml.cpu = cpu_xml
vmxml.sync()
logging.info("Multi-NUMA configuration applied: %d cells",
numa_cells)
else:
vmxml.set_vm_vcpus(vm_name, vcpu_max_num, vcpu_current_num,
topology_correction=topology_correction)

vm.start()
vm_uptime_init = vm.uptime()
if with_stress:
Expand Down