libvirt: fix incorrect host cpus giving to emulator threads when RT
Realtime guarantees in certain operating systems require that the thread that is running the QEMU emulator is pinned to a physical CPU that is *not* the same as any physical CPU that the vCPUs for a realtime guest are pinned to. This patch ensures that the value of the hw:cpu_realtime_mask flavor extraspec property is respected when creating the libvirt configuration XML and sets emulatorpin values to a physical CPU matching the hw:cpu_realtime_mask value. Change-Id: I7f50dde0753b059a690dc50172fee645c94b8e5b Closes-Bug: #1614054
This commit is contained in:
@@ -2773,15 +2773,15 @@ class LibvirtConnTestCase(test.NoDBTestCase):
|
||||
instance_topology = objects.InstanceNUMATopology(
|
||||
cells=[
|
||||
objects.InstanceNUMACell(
|
||||
id=1, cpuset=set([0, 1]),
|
||||
id=2, cpuset=set([0, 1]),
|
||||
memory=1024, pagesize=2048),
|
||||
objects.InstanceNUMACell(
|
||||
id=2, cpuset=set([2, 3]),
|
||||
id=3, cpuset=set([2, 3]),
|
||||
memory=1024, pagesize=2048)])
|
||||
instance_ref = objects.Instance(**self.test_instance)
|
||||
instance_ref.numa_topology = instance_topology
|
||||
image_meta = objects.ImageMeta.from_dict(self.test_image_meta)
|
||||
flavor = objects.Flavor(memory_mb=2048, vcpus=2, root_gb=496,
|
||||
flavor = objects.Flavor(memory_mb=2048, vcpus=4, root_gb=496,
|
||||
ephemeral_gb=8128, swap=33550336, name='fake',
|
||||
extra_specs={
|
||||
"hw:cpu_realtime": "yes",
|
||||
@@ -2811,7 +2811,7 @@ class LibvirtConnTestCase(test.NoDBTestCase):
|
||||
return_value=caps),
|
||||
mock.patch.object(
|
||||
hardware, 'get_vcpu_pin_set',
|
||||
return_value=set([2, 3, 4, 5])),
|
||||
return_value=set([4, 5, 6, 7])),
|
||||
mock.patch.object(host.Host, 'get_online_cpus',
|
||||
return_value=set(range(8))),
|
||||
):
|
||||
@@ -2842,8 +2842,21 @@ class LibvirtConnTestCase(test.NoDBTestCase):
|
||||
|
||||
self.assertEqual(1, len(cfg.cputune.vcpusched))
|
||||
self.assertEqual("fifo", cfg.cputune.vcpusched[0].scheduler)
|
||||
|
||||
# Ensure vCPUs 0-1 are pinned on host CPUs 4-5 and 2-3 are
|
||||
# set on host CPUs 6-7 according the realtime mask ^0-1
|
||||
self.assertEqual(set([4, 5]), cfg.cputune.vcpupin[0].cpuset)
|
||||
self.assertEqual(set([4, 5]), cfg.cputune.vcpupin[1].cpuset)
|
||||
self.assertEqual(set([6, 7]), cfg.cputune.vcpupin[2].cpuset)
|
||||
self.assertEqual(set([6, 7]), cfg.cputune.vcpupin[3].cpuset)
|
||||
|
||||
# We ensure that emulator threads are pinned on host CPUs
|
||||
# 4-5 which are "normal" vCPUs
|
||||
self.assertEqual(set([4, 5]), cfg.cputune.emulatorpin.cpuset)
|
||||
|
||||
# We ensure that the vCPUs RT are 2-3 set to the host CPUs
|
||||
# which are 6, 7
|
||||
self.assertEqual(set([2, 3]), cfg.cputune.vcpusched[0].vcpus)
|
||||
self.assertEqual(set([0, 1]), cfg.cputune.emulatorpin.cpuset)
|
||||
|
||||
def test_get_cpu_numa_config_from_instance(self):
|
||||
topology = objects.InstanceNUMATopology(cells=[
|
||||
|
||||
@@ -2768,30 +2768,32 @@ class CPUPinningTestCase(test.NoDBTestCase, _CPUPinningTestCaseBase):
|
||||
|
||||
class CPURealtimeTestCase(test.NoDBTestCase):
|
||||
def test_success_flavor(self):
|
||||
flavor = {"extra_specs": {"hw:cpu_realtime_mask": "^1"}}
|
||||
flavor = objects.Flavor(vcpus=3, memory_mb=2048,
|
||||
extra_specs={"hw:cpu_realtime_mask": "^1"})
|
||||
image = objects.ImageMeta.from_dict({})
|
||||
rt, em = hw.vcpus_realtime_topology(set([0, 1, 2]), flavor, image)
|
||||
rt = hw.vcpus_realtime_topology(flavor, image)
|
||||
self.assertEqual(set([0, 2]), rt)
|
||||
self.assertEqual(set([1]), em)
|
||||
|
||||
def test_success_image(self):
|
||||
flavor = {"extra_specs": {}}
|
||||
flavor = objects.Flavor(vcpus=3, memory_mb=2048,
|
||||
extra_specs={"hw:cpu_realtime_mask": "^1"})
|
||||
image = objects.ImageMeta.from_dict(
|
||||
{"properties": {"hw_cpu_realtime_mask": "^0-1"}})
|
||||
rt, em = hw.vcpus_realtime_topology(set([0, 1, 2]), flavor, image)
|
||||
rt = hw.vcpus_realtime_topology(flavor, image)
|
||||
self.assertEqual(set([2]), rt)
|
||||
self.assertEqual(set([0, 1]), em)
|
||||
|
||||
def test_no_mask_configured(self):
|
||||
flavor = {"extra_specs": {}}
|
||||
flavor = objects.Flavor(vcpus=3, memory_mb=2048,
|
||||
extra_specs={})
|
||||
image = objects.ImageMeta.from_dict({"properties": {}})
|
||||
self.assertRaises(
|
||||
exception.RealtimeMaskNotFoundOrInvalid,
|
||||
hw.vcpus_realtime_topology, set([0, 1, 2]), flavor, image)
|
||||
hw.vcpus_realtime_topology, flavor, image)
|
||||
|
||||
def test_mask_badly_configured(self):
|
||||
flavor = {"extra_specs": {"hw:cpu_realtime_mask": "^0-2"}}
|
||||
flavor = objects.Flavor(vcpus=3, memory_mb=2048,
|
||||
extra_specs={"hw:cpu_realtime_mask": "^0-2"})
|
||||
image = objects.ImageMeta.from_dict({"properties": {}})
|
||||
self.assertRaises(
|
||||
exception.RealtimeMaskNotFoundOrInvalid,
|
||||
hw.vcpus_realtime_topology, set([0, 1, 2]), flavor, image)
|
||||
hw.vcpus_realtime_topology, flavor, image)
|
||||
|
||||
Reference in New Issue
Block a user