Fix for bug 2140537
If a guest has pinned CPUs the domain XML's <iothreadpin> should have iothread attribute also. Closes-Bug: #2140537 Change-Id: I5c2df747a3fdfbd2ee31d50a3d716a0ccc787e15 Signed-off-by: lajoskatona <lajos.katona@est.tech>
This commit is contained in:
committed by
Lajos Katona
parent
76d796193c
commit
873aee5e95
Vendored
+8
-21
@@ -1233,6 +1233,14 @@ class Domain(object):
|
|||||||
definition['iothreads'] = iothreads.text
|
definition['iothreads'] = iothreads.text
|
||||||
|
|
||||||
iothread_pin = tree.find('./cputune/iothreadpin')
|
iothread_pin = tree.find('./cputune/iothreadpin')
|
||||||
|
if iothread_pin is not None and iothread_pin.get('iothread') is None:
|
||||||
|
raise make_libvirtError(
|
||||||
|
libvirtError,
|
||||||
|
"XML error: Missing required attribute 'iothread' "
|
||||||
|
"in element 'iothreadpin'",
|
||||||
|
error_code=VIR_ERR_XML_ERROR,
|
||||||
|
error_domain=VIR_FROM_DOMAIN
|
||||||
|
)
|
||||||
if iothread_pin is not None:
|
if iothread_pin is not None:
|
||||||
definition['iothread_pin'] = iothread_pin.get('cpuset')
|
definition['iothread_pin'] = iothread_pin.get('cpuset')
|
||||||
|
|
||||||
@@ -2095,27 +2103,6 @@ class Connection(object):
|
|||||||
self._emit_lifecycle(dom, VIR_DOMAIN_EVENT_DEFINED, 0)
|
self._emit_lifecycle(dom, VIR_DOMAIN_EVENT_DEFINED, 0)
|
||||||
return dom
|
return dom
|
||||||
|
|
||||||
# TODO(lajoskatona): Move this validation to defineXML once fix for
|
|
||||||
# bug/2140537 is merged.
|
|
||||||
# This method is only used temporarily from
|
|
||||||
# nova/tests/functional/regressions/test_bug_2140537.py
|
|
||||||
def _defineXMLIOThreads(self, xml):
|
|
||||||
xml_doc = etree.fromstring(xml.encode('utf-8'))
|
|
||||||
iothreadpin = xml_doc.find('./cputune/iothreadpin')
|
|
||||||
|
|
||||||
if iothreadpin is not None and iothreadpin.get('iothread') is None:
|
|
||||||
raise make_libvirtError(
|
|
||||||
libvirtError,
|
|
||||||
"XML error: Missing required attribute 'iothread' "
|
|
||||||
"in element 'iothreadpin'",
|
|
||||||
error_code=VIR_ERR_XML_ERROR,
|
|
||||||
error_domain=VIR_FROM_DOMAIN)
|
|
||||||
|
|
||||||
dom = Domain(connection=self, running=False, transient=False, xml=xml)
|
|
||||||
self._vms[dom.name()] = dom
|
|
||||||
self._emit_lifecycle(dom, VIR_DOMAIN_EVENT_DEFINED, 0)
|
|
||||||
return dom
|
|
||||||
|
|
||||||
def createXML(self, xml, flags):
|
def createXML(self, xml, flags):
|
||||||
dom = Domain(connection=self, running=True, transient=True, xml=xml)
|
dom = Domain(connection=self, running=True, transient=True, xml=xml)
|
||||||
self._vms[dom.name()] = dom
|
self._vms[dom.name()] = dom
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ in element 'iothreadpin'".
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
from lxml import etree
|
from lxml import etree
|
||||||
from unittest import mock
|
|
||||||
|
|
||||||
from nova.tests.fixtures import libvirt as fakelibvirt
|
from nova.tests.fixtures import libvirt as fakelibvirt
|
||||||
from nova.tests.functional import integrated_helpers
|
from nova.tests.functional import integrated_helpers
|
||||||
@@ -46,15 +45,6 @@ class TestIOThreadPinningPinnedCPU(
|
|||||||
ADDITIONAL_FILTERS = ['NUMATopologyFilter']
|
ADDITIONAL_FILTERS = ['NUMATopologyFilter']
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
# TODO(lajoskatona): remove this patch when the fix for
|
|
||||||
# bug/2140537 is merged, and the libvirt fixture has the
|
|
||||||
# necessary validation for XML fields for IOThreads.
|
|
||||||
patcher = mock.patch.object(
|
|
||||||
fakelibvirt.Connection, 'defineXML',
|
|
||||||
fakelibvirt.Connection._defineXMLIOThreads)
|
|
||||||
patcher.start()
|
|
||||||
self.addCleanup(patcher.stop)
|
|
||||||
|
|
||||||
super().setUp()
|
super().setUp()
|
||||||
self.hostname = self.start_compute(
|
self.hostname = self.start_compute(
|
||||||
hostname='host1',
|
hostname='host1',
|
||||||
@@ -91,20 +81,34 @@ class TestIOThreadPinningPinnedCPU(
|
|||||||
|
|
||||||
# BUG: This fails with libvirt error about missing 'iothread' attribute
|
# BUG: This fails with libvirt error about missing 'iothread' attribute
|
||||||
# The server creation will fail and go to ERROR state
|
# The server creation will fail and go to ERROR state
|
||||||
|
# server = self._create_server(
|
||||||
|
# flavor_id=flavor, host='host1', networks='none',
|
||||||
|
# expected_state='ERROR')
|
||||||
server = self._create_server(
|
server = self._create_server(
|
||||||
flavor_id=flavor, host='host1', networks='none',
|
flavor_id=flavor, host='host1', networks='none',
|
||||||
expected_state='ERROR')
|
expected_state='ACTIVE')
|
||||||
|
|
||||||
# Verify the server is in ERROR state due to the libvirt XML error
|
# Verify the server is in ERROR state due to the libvirt XML error
|
||||||
self.assertEqual('ERROR', server['status'])
|
# self.assertEqual('ERROR', server['status'])
|
||||||
|
|
||||||
# Check the fault message contains the libvirt error
|
# Check the fault message contains the libvirt error
|
||||||
self.assertIn('Exceeded maximum number of retries',
|
# self.assertIn('Exceeded maximum number of retries',
|
||||||
server['fault']['message'])
|
# server['fault']['message'])
|
||||||
# Check the logs for the exception
|
# Check the logs for the exception
|
||||||
self.assertIn("Missing required attribute 'iothread'",
|
# self.assertIn("Missing required attribute 'iothread'",
|
||||||
self.stdlog.logger.output)
|
# self.stdlog.logger.output)
|
||||||
self.assertIn("element 'iothreadpin'", self.stdlog.logger.output)
|
# self.assertIn("element 'iothreadpin'", self.stdlog.logger.output)
|
||||||
|
|
||||||
|
# Get source XML and verify pinning matches cpu_shared_set
|
||||||
|
conn = self.host.driver._host.get_connection()
|
||||||
|
dom = conn.lookupByUUIDString(server['id'])
|
||||||
|
srv_xml = dom.XMLDesc(0)
|
||||||
|
srv_emulatorpin = self._get_xml_element(
|
||||||
|
srv_xml, './cputune/emulatorpin')
|
||||||
|
srv_iothreadpin = self._get_xml_element(
|
||||||
|
srv_xml, './cputune/iothreadpin')
|
||||||
|
self.assertIsNotNone(srv_emulatorpin)
|
||||||
|
self.assertIsNotNone(srv_iothreadpin)
|
||||||
|
|
||||||
def test_iothread_pinning_explicit_numa(self):
|
def test_iothread_pinning_explicit_numa(self):
|
||||||
"""Test iothread pinning with explicit multi-node NUMA topology."""
|
"""Test iothread pinning with explicit multi-node NUMA topology."""
|
||||||
@@ -120,46 +124,46 @@ class TestIOThreadPinningPinnedCPU(
|
|||||||
flavor = self._create_flavor(vcpu=4, extra_spec=extra_spec)
|
flavor = self._create_flavor(vcpu=4, extra_spec=extra_spec)
|
||||||
|
|
||||||
# Server should go ACTIVE
|
# Server should go ACTIVE
|
||||||
# server = self._create_server(
|
|
||||||
# flavor_id=flavor, host='host1', networks='none',
|
|
||||||
# expected_state='ACTIVE')
|
|
||||||
server = self._create_server(
|
server = self._create_server(
|
||||||
flavor_id=flavor, host='host1', networks='none',
|
flavor_id=flavor, host='host1', networks='none',
|
||||||
expected_state='ERROR')
|
expected_state='ACTIVE')
|
||||||
|
# server = self._create_server(
|
||||||
|
# flavor_id=flavor, host='host1', networks='none',
|
||||||
|
# expected_state='ERROR')
|
||||||
|
|
||||||
# conn = self.host.driver._host.get_connection()
|
conn = self.host.driver._host.get_connection()
|
||||||
# dom = conn.lookupByUUIDString(server['id'])
|
dom = conn.lookupByUUIDString(server['id'])
|
||||||
# srv_xml = dom.XMLDesc(0)
|
srv_xml = dom.XMLDesc(0)
|
||||||
|
|
||||||
# # Should have iothreads element
|
# Should have iothreads element
|
||||||
# srv_iothread = self._get_xml_element(srv_xml, './iothreads')
|
srv_iothread = self._get_xml_element(srv_xml, './iothreads')
|
||||||
# self.assertIsNotNone(srv_iothread)
|
self.assertIsNotNone(srv_iothread)
|
||||||
# self.assertEqual('1', srv_iothread.text)
|
self.assertEqual('1', srv_iothread.text)
|
||||||
|
|
||||||
# # Should have emulatorpin and iothreadpin
|
# Should have emulatorpin and iothreadpin
|
||||||
# srv_emulatorpin = self._get_xml_element(
|
srv_emulatorpin = self._get_xml_element(
|
||||||
# srv_xml, './cputune/emulatorpin')
|
srv_xml, './cputune/emulatorpin')
|
||||||
# srv_iothreadpin = self._get_xml_element(
|
srv_iothreadpin = self._get_xml_element(
|
||||||
# srv_xml, './cputune/iothreadpin')
|
srv_xml, './cputune/iothreadpin')
|
||||||
# self.assertIsNotNone(srv_emulatorpin)
|
self.assertIsNotNone(srv_emulatorpin)
|
||||||
# self.assertIsNotNone(srv_iothreadpin)
|
self.assertIsNotNone(srv_iothreadpin)
|
||||||
|
|
||||||
# # iothreadpin should have iothread attribute set to 1
|
# iothreadpin should have iothread attribute set to 1
|
||||||
# self.assertEqual('1', srv_iothreadpin.get('iothread'))
|
self.assertEqual('1', srv_iothreadpin.get('iothread'))
|
||||||
|
|
||||||
# # Both should be pinned to the union of NUMA nodes
|
# Both should be pinned to the union of NUMA nodes
|
||||||
# self.assertEqual(srv_emulatorpin.get('cpuset'),
|
self.assertEqual(srv_emulatorpin.get('cpuset'),
|
||||||
# srv_iothreadpin.get('cpuset'))
|
srv_iothreadpin.get('cpuset'))
|
||||||
|
|
||||||
self.assertEqual('ERROR', server['status'])
|
# self.assertEqual('ERROR', server['status'])
|
||||||
|
|
||||||
# Check the fault message contains the libvirt error
|
# # Check the fault message contains the libvirt error
|
||||||
self.assertIn('Exceeded maximum number of retries',
|
# self.assertIn('Exceeded maximum number of retries',
|
||||||
server['fault']['message'])
|
# server['fault']['message'])
|
||||||
# Check the logs for the exception
|
# # Check the logs for the exception
|
||||||
self.assertIn("Missing required attribute 'iothread'",
|
# self.assertIn("Missing required attribute 'iothread'",
|
||||||
self.stdlog.logger.output)
|
# self.stdlog.logger.output)
|
||||||
self.assertIn("element 'iothreadpin'", self.stdlog.logger.output)
|
# self.assertIn("element 'iothreadpin'", self.stdlog.logger.output)
|
||||||
|
|
||||||
def test_iothread_pinning_isolated_emulator(self):
|
def test_iothread_pinning_isolated_emulator(self):
|
||||||
"""Test iothread pinning with isolated emulator threads policy."""
|
"""Test iothread pinning with isolated emulator threads policy."""
|
||||||
@@ -174,52 +178,52 @@ class TestIOThreadPinningPinnedCPU(
|
|||||||
}
|
}
|
||||||
flavor = self._create_flavor(vcpu=2, extra_spec=extra_spec)
|
flavor = self._create_flavor(vcpu=2, extra_spec=extra_spec)
|
||||||
|
|
||||||
server = self._create_server(
|
|
||||||
flavor_id=flavor, host='host1', networks='none',
|
|
||||||
expected_state='ERROR')
|
|
||||||
# Server should go ACTIVE
|
|
||||||
# server = self._create_server(
|
# server = self._create_server(
|
||||||
# flavor_id=flavor, host='host1', networks='none',
|
# flavor_id=flavor, host='host1', networks='none',
|
||||||
# expected_state='ACTIVE')
|
# expected_state='ERROR')
|
||||||
|
# Server should go ACTIVE
|
||||||
|
server = self._create_server(
|
||||||
|
flavor_id=flavor, host='host1', networks='none',
|
||||||
|
expected_state='ACTIVE')
|
||||||
|
|
||||||
# conn = self.host.driver._host.get_connection()
|
conn = self.host.driver._host.get_connection()
|
||||||
# dom = conn.lookupByUUIDString(server['id'])
|
dom = conn.lookupByUUIDString(server['id'])
|
||||||
# srv_xml = dom.XMLDesc(0)
|
srv_xml = dom.XMLDesc(0)
|
||||||
|
|
||||||
# # Should have iothreads element
|
# Should have iothreads element
|
||||||
# srv_iothread = self._get_xml_element(srv_xml, './iothreads')
|
srv_iothread = self._get_xml_element(srv_xml, './iothreads')
|
||||||
# self.assertIsNotNone(srv_iothread)
|
self.assertIsNotNone(srv_iothread)
|
||||||
# self.assertEqual('1', srv_iothread.text)
|
self.assertEqual('1', srv_iothread.text)
|
||||||
|
|
||||||
# # Should have emulatorpin and iothreadpin
|
# Should have emulatorpin and iothreadpin
|
||||||
# srv_emulatorpin = self._get_xml_element(
|
srv_emulatorpin = self._get_xml_element(
|
||||||
# srv_xml, './cputune/emulatorpin')
|
srv_xml, './cputune/emulatorpin')
|
||||||
# srv_iothreadpin = self._get_xml_element(
|
srv_iothreadpin = self._get_xml_element(
|
||||||
# srv_xml, './cputune/iothreadpin')
|
srv_xml, './cputune/iothreadpin')
|
||||||
# self.assertIsNotNone(srv_emulatorpin)
|
self.assertIsNotNone(srv_emulatorpin)
|
||||||
# self.assertIsNotNone(srv_iothreadpin)
|
self.assertIsNotNone(srv_iothreadpin)
|
||||||
|
|
||||||
# # iothreadpin should have iothread attribute set to 1
|
# iothreadpin should have iothread attribute set to 1
|
||||||
# self.assertEqual('1', srv_iothreadpin.get('iothread'))
|
self.assertEqual('1', srv_iothreadpin.get('iothread'))
|
||||||
|
|
||||||
# # Both should be pinned to the same reserved/isolated CPU
|
# Both should be pinned to the same reserved/isolated CPU
|
||||||
# self.assertEqual(srv_emulatorpin.get('cpuset'),
|
self.assertEqual(srv_emulatorpin.get('cpuset'),
|
||||||
# srv_iothreadpin.get('cpuset'))
|
srv_iothreadpin.get('cpuset'))
|
||||||
|
|
||||||
# # Should be pinned to a single CPU (the reserved one)
|
# Should be pinned to a single CPU (the reserved one)
|
||||||
# # With vcpu=2 and isolate policy, one extra CPU is reserved
|
# With vcpu=2 and isolate policy, one extra CPU is reserved
|
||||||
# cpuset = srv_iothreadpin.get('cpuset')
|
cpuset = srv_iothreadpin.get('cpuset')
|
||||||
# # The cpuset should be a single CPU from cpu_dedicated_set
|
# The cpuset should be a single CPU from cpu_dedicated_set
|
||||||
# self.assertIsNotNone(cpuset)
|
self.assertIsNotNone(cpuset)
|
||||||
self.assertEqual('ERROR', server['status'])
|
# self.assertEqual('ERROR', server['status'])
|
||||||
|
|
||||||
# Check the fault message contains the libvirt error
|
# # Check the fault message contains the libvirt error
|
||||||
self.assertIn('Exceeded maximum number of retries',
|
# self.assertIn('Exceeded maximum number of retries',
|
||||||
server['fault']['message'])
|
# server['fault']['message'])
|
||||||
# Check the logs for the exception
|
# # Check the logs for the exception
|
||||||
self.assertIn("Missing required attribute 'iothread'",
|
# self.assertIn("Missing required attribute 'iothread'",
|
||||||
self.stdlog.logger.output)
|
# self.stdlog.logger.output)
|
||||||
self.assertIn("element 'iothreadpin'", self.stdlog.logger.output)
|
# self.assertIn("element 'iothreadpin'", self.stdlog.logger.output)
|
||||||
|
|
||||||
def test_iothread_pinning_shared_emulator(self):
|
def test_iothread_pinning_shared_emulator(self):
|
||||||
"""Test iothread pinning with shared emulator threads policy."""
|
"""Test iothread pinning with shared emulator threads policy."""
|
||||||
@@ -234,48 +238,48 @@ class TestIOThreadPinningPinnedCPU(
|
|||||||
}
|
}
|
||||||
flavor = self._create_flavor(vcpu=2, extra_spec=extra_spec)
|
flavor = self._create_flavor(vcpu=2, extra_spec=extra_spec)
|
||||||
|
|
||||||
server = self._create_server(
|
|
||||||
flavor_id=flavor, host='host1', networks='none',
|
|
||||||
expected_state='ERROR')
|
|
||||||
# Server should go ACTIVE
|
|
||||||
# server = self._create_server(
|
# server = self._create_server(
|
||||||
# flavor_id=flavor, host='host1', networks='none',
|
# flavor_id=flavor, host='host1', networks='none',
|
||||||
# expected_state='ACTIVE')
|
# expected_state='ERROR')
|
||||||
|
# Server should go ACTIVE
|
||||||
|
server = self._create_server(
|
||||||
|
flavor_id=flavor, host='host1', networks='none',
|
||||||
|
expected_state='ACTIVE')
|
||||||
|
|
||||||
# conn = self.host.driver._host.get_connection()
|
conn = self.host.driver._host.get_connection()
|
||||||
# dom = conn.lookupByUUIDString(server['id'])
|
dom = conn.lookupByUUIDString(server['id'])
|
||||||
# srv_xml = dom.XMLDesc(0)
|
srv_xml = dom.XMLDesc(0)
|
||||||
|
|
||||||
# # Should have iothreads element
|
# Should have iothreads element
|
||||||
# srv_iothread = self._get_xml_element(srv_xml, './iothreads')
|
srv_iothread = self._get_xml_element(srv_xml, './iothreads')
|
||||||
# self.assertIsNotNone(srv_iothread)
|
self.assertIsNotNone(srv_iothread)
|
||||||
# self.assertEqual('1', srv_iothread.text)
|
self.assertEqual('1', srv_iothread.text)
|
||||||
|
|
||||||
# # Should have emulatorpin and iothreadpin
|
# Should have emulatorpin and iothreadpin
|
||||||
# srv_emulatorpin = self._get_xml_element(
|
srv_emulatorpin = self._get_xml_element(
|
||||||
# srv_xml, './cputune/emulatorpin')
|
srv_xml, './cputune/emulatorpin')
|
||||||
# srv_iothreadpin = self._get_xml_element(
|
srv_iothreadpin = self._get_xml_element(
|
||||||
# srv_xml, './cputune/iothreadpin')
|
srv_xml, './cputune/iothreadpin')
|
||||||
# self.assertIsNotNone(srv_emulatorpin)
|
self.assertIsNotNone(srv_emulatorpin)
|
||||||
# self.assertIsNotNone(srv_iothreadpin)
|
self.assertIsNotNone(srv_iothreadpin)
|
||||||
|
|
||||||
# # iothreadpin should have iothread attribute set to 1
|
# iothreadpin should have iothread attribute set to 1
|
||||||
# self.assertEqual('1', srv_iothreadpin.get('iothread'))
|
self.assertEqual('1', srv_iothreadpin.get('iothread'))
|
||||||
|
|
||||||
# # Both should be pinned to cpu_shared_set (0-1)
|
# Both should be pinned to cpu_shared_set (0-1)
|
||||||
# self.assertEqual(srv_emulatorpin.get('cpuset'),
|
self.assertEqual(srv_emulatorpin.get('cpuset'),
|
||||||
# srv_iothreadpin.get('cpuset'))
|
srv_iothreadpin.get('cpuset'))
|
||||||
# self.assertEqual('0-1', srv_iothreadpin.get('cpuset'))
|
self.assertEqual('0-1', srv_iothreadpin.get('cpuset'))
|
||||||
|
|
||||||
self.assertEqual('ERROR', server['status'])
|
# self.assertEqual('ERROR', server['status'])
|
||||||
|
|
||||||
# Check the fault message contains the libvirt error
|
# # Check the fault message contains the libvirt error
|
||||||
self.assertIn('Exceeded maximum number of retries',
|
# self.assertIn('Exceeded maximum number of retries',
|
||||||
server['fault']['message'])
|
# server['fault']['message'])
|
||||||
# Check the logs for the exception
|
# # Check the logs for the exception
|
||||||
self.assertIn("Missing required attribute 'iothread'",
|
# self.assertIn("Missing required attribute 'iothread'",
|
||||||
self.stdlog.logger.output)
|
# self.stdlog.logger.output)
|
||||||
self.assertIn("element 'iothreadpin'", self.stdlog.logger.output)
|
# self.assertIn("element 'iothreadpin'", self.stdlog.logger.output)
|
||||||
|
|
||||||
def test_iothread_no_pinning(self):
|
def test_iothread_no_pinning(self):
|
||||||
# No CPU pinning (shared CPUs only)
|
# No CPU pinning (shared CPUs only)
|
||||||
|
|||||||
@@ -4054,8 +4054,9 @@ class LibvirtConfigGuestCPUTuneTest(LibvirtConfigBaseTest):
|
|||||||
cputune.emulatorpin = emu
|
cputune.emulatorpin = emu
|
||||||
|
|
||||||
iot = config.LibvirtConfigGuestCPUTuneIOThreadPin()
|
iot = config.LibvirtConfigGuestCPUTuneIOThreadPin()
|
||||||
|
iot.iothread = 1
|
||||||
iot.cpuset = set([0, 1, 2, 3, 4, 5, 6, 7])
|
iot.cpuset = set([0, 1, 2, 3, 4, 5, 6, 7])
|
||||||
cputune.iothreadpin = iot
|
cputune.iothreadpin.append(iot)
|
||||||
|
|
||||||
sch0 = config.LibvirtConfigGuestCPUTuneVCPUSched()
|
sch0 = config.LibvirtConfigGuestCPUTuneVCPUSched()
|
||||||
sch0.vcpus = set([0, 1, 2, 3])
|
sch0.vcpus = set([0, 1, 2, 3])
|
||||||
@@ -4071,7 +4072,7 @@ class LibvirtConfigGuestCPUTuneTest(LibvirtConfigBaseTest):
|
|||||||
self.assertXmlEqual("""
|
self.assertXmlEqual("""
|
||||||
<cputune>
|
<cputune>
|
||||||
<emulatorpin cpuset="0-7"/>
|
<emulatorpin cpuset="0-7"/>
|
||||||
<iothreadpin cpuset="0-7"/>
|
<iothreadpin iothread="1" cpuset="0-7"/>
|
||||||
<vcpupin vcpu="0" cpuset="0-1"/>
|
<vcpupin vcpu="0" cpuset="0-1"/>
|
||||||
<vcpupin vcpu="1" cpuset="2-3"/>
|
<vcpupin vcpu="1" cpuset="2-3"/>
|
||||||
<vcpupin vcpu="2" cpuset="4-5"/>
|
<vcpupin vcpu="2" cpuset="4-5"/>
|
||||||
|
|||||||
@@ -5301,11 +5301,14 @@ class LibvirtConnTestCase(test.NoDBTestCase,
|
|||||||
cfg = drvr._get_guest_config(instance_ref, [],
|
cfg = drvr._get_guest_config(instance_ref, [],
|
||||||
image_meta, disk_info)
|
image_meta, disk_info)
|
||||||
|
|
||||||
self.assertIsInstance(cfg.cputune.iothreadpin,
|
self.assertIsInstance(cfg.cputune.iothreadpin, list)
|
||||||
|
self.assertEqual(1, len(cfg.cputune.iothreadpin))
|
||||||
|
self.assertIsInstance(cfg.cputune.iothreadpin[0],
|
||||||
vconfig.LibvirtConfigGuestCPUTuneIOThreadPin)
|
vconfig.LibvirtConfigGuestCPUTuneIOThreadPin)
|
||||||
|
self.assertEqual(1, cfg.cputune.iothreadpin[0].iothread)
|
||||||
self.assertEqual(cfg.cputune.emulatorpin.cpuset,
|
self.assertEqual(cfg.cputune.emulatorpin.cpuset,
|
||||||
cfg.cputune.iothreadpin.cpuset)
|
cfg.cputune.iothreadpin[0].cpuset)
|
||||||
self.assertEqual(set([6]), cfg.cputune.iothreadpin.cpuset)
|
self.assertEqual(set([6]), cfg.cputune.iothreadpin[0].cpuset)
|
||||||
|
|
||||||
@mock.patch.object(host.Host, "_check_machine_type", new=mock.Mock())
|
@mock.patch.object(host.Host, "_check_machine_type", new=mock.Mock())
|
||||||
def test_get_guest_config_iothreadpin_shared_emulator_threads(self):
|
def test_get_guest_config_iothreadpin_shared_emulator_threads(self):
|
||||||
@@ -5356,11 +5359,14 @@ class LibvirtConnTestCase(test.NoDBTestCase,
|
|||||||
cfg = drvr._get_guest_config(instance_ref, [],
|
cfg = drvr._get_guest_config(instance_ref, [],
|
||||||
image_meta, disk_info)
|
image_meta, disk_info)
|
||||||
|
|
||||||
self.assertIsInstance(cfg.cputune.iothreadpin,
|
self.assertIsInstance(cfg.cputune.iothreadpin, list)
|
||||||
|
self.assertEqual(1, len(cfg.cputune.iothreadpin))
|
||||||
|
self.assertIsInstance(cfg.cputune.iothreadpin[0],
|
||||||
vconfig.LibvirtConfigGuestCPUTuneIOThreadPin)
|
vconfig.LibvirtConfigGuestCPUTuneIOThreadPin)
|
||||||
|
self.assertEqual(1, cfg.cputune.iothreadpin[0].iothread)
|
||||||
self.assertEqual(cfg.cputune.emulatorpin.cpuset,
|
self.assertEqual(cfg.cputune.emulatorpin.cpuset,
|
||||||
cfg.cputune.iothreadpin.cpuset)
|
cfg.cputune.iothreadpin[0].cpuset)
|
||||||
self.assertEqual(set([1, 2]), cfg.cputune.iothreadpin.cpuset)
|
self.assertEqual(set([1, 2]), cfg.cputune.iothreadpin[0].cpuset)
|
||||||
|
|
||||||
@mock.patch.object(host.Host, "_check_machine_type", new=mock.Mock())
|
@mock.patch.object(host.Host, "_check_machine_type", new=mock.Mock())
|
||||||
def test_get_guest_config_iothreadpin_numa_topology(self):
|
def test_get_guest_config_iothreadpin_numa_topology(self):
|
||||||
@@ -5407,11 +5413,15 @@ class LibvirtConnTestCase(test.NoDBTestCase,
|
|||||||
cfg = drvr._get_guest_config(instance_ref, [],
|
cfg = drvr._get_guest_config(instance_ref, [],
|
||||||
image_meta, disk_info)
|
image_meta, disk_info)
|
||||||
|
|
||||||
self.assertIsInstance(cfg.cputune.iothreadpin,
|
self.assertIsInstance(cfg.cputune.iothreadpin, list)
|
||||||
|
self.assertEqual(1, len(cfg.cputune.iothreadpin))
|
||||||
|
self.assertIsInstance(cfg.cputune.iothreadpin[0],
|
||||||
vconfig.LibvirtConfigGuestCPUTuneIOThreadPin)
|
vconfig.LibvirtConfigGuestCPUTuneIOThreadPin)
|
||||||
|
self.assertEqual(1, cfg.cputune.iothreadpin[0].iothread)
|
||||||
self.assertEqual(cfg.cputune.emulatorpin.cpuset,
|
self.assertEqual(cfg.cputune.emulatorpin.cpuset,
|
||||||
cfg.cputune.iothreadpin.cpuset)
|
cfg.cputune.iothreadpin[0].cpuset)
|
||||||
self.assertEqual(set([0, 1, 2, 3]), cfg.cputune.iothreadpin.cpuset)
|
self.assertEqual(set([0, 1, 2, 3]),
|
||||||
|
cfg.cputune.iothreadpin[0].cpuset)
|
||||||
|
|
||||||
def test_get_guest_config_numa_host_instance_shared_emulthreads_err(
|
def test_get_guest_config_numa_host_instance_shared_emulthreads_err(
|
||||||
self):
|
self):
|
||||||
|
|||||||
@@ -2675,6 +2675,7 @@ class LibvirtConfigGuestCPUTuneIOThreadPin(LibvirtConfigObject):
|
|||||||
**kwargs)
|
**kwargs)
|
||||||
|
|
||||||
self.cpuset = None
|
self.cpuset = None
|
||||||
|
self.iothread = None
|
||||||
|
|
||||||
def format_dom(self):
|
def format_dom(self):
|
||||||
root = super(LibvirtConfigGuestCPUTuneIOThreadPin, self).format_dom()
|
root = super(LibvirtConfigGuestCPUTuneIOThreadPin, self).format_dom()
|
||||||
@@ -2682,6 +2683,8 @@ class LibvirtConfigGuestCPUTuneIOThreadPin(LibvirtConfigObject):
|
|||||||
if self.cpuset is not None:
|
if self.cpuset is not None:
|
||||||
root.set("cpuset",
|
root.set("cpuset",
|
||||||
hardware.format_cpu_spec(self.cpuset))
|
hardware.format_cpu_spec(self.cpuset))
|
||||||
|
if self.iothread is not None:
|
||||||
|
root.set("iothread", str(self.iothread))
|
||||||
|
|
||||||
return root
|
return root
|
||||||
|
|
||||||
@@ -2721,7 +2724,7 @@ class LibvirtConfigGuestCPUTune(LibvirtConfigObject):
|
|||||||
self.period = None
|
self.period = None
|
||||||
self.vcpupin = []
|
self.vcpupin = []
|
||||||
self.emulatorpin = None
|
self.emulatorpin = None
|
||||||
self.iothreadpin = None
|
self.iothreadpin = []
|
||||||
self.vcpusched = []
|
self.vcpusched = []
|
||||||
|
|
||||||
def format_dom(self):
|
def format_dom(self):
|
||||||
@@ -2736,8 +2739,11 @@ class LibvirtConfigGuestCPUTune(LibvirtConfigObject):
|
|||||||
|
|
||||||
if self.emulatorpin is not None:
|
if self.emulatorpin is not None:
|
||||||
root.append(self.emulatorpin.format_dom())
|
root.append(self.emulatorpin.format_dom())
|
||||||
if self.iothreadpin is not None:
|
# Only render <iothreadpin> if fully configured to avoid bug #2140537:
|
||||||
root.append(self.iothreadpin.format_dom())
|
# libvirt requires 'iothread' attribute and non-empty 'cpuset'
|
||||||
|
for pin in self.iothreadpin:
|
||||||
|
if pin.iothread is not None and pin.cpuset:
|
||||||
|
root.append(pin.format_dom())
|
||||||
for vcpu in self.vcpupin:
|
for vcpu in self.vcpupin:
|
||||||
root.append(vcpu.format_dom())
|
root.append(vcpu.format_dom())
|
||||||
for sched in self.vcpusched:
|
for sched in self.vcpusched:
|
||||||
|
|||||||
@@ -6462,6 +6462,9 @@ class LibvirtDriver(driver.ComputeDriver):
|
|||||||
|
|
||||||
return emulatorpin_cpuset
|
return emulatorpin_cpuset
|
||||||
|
|
||||||
|
def _get_guest_iothread(self):
|
||||||
|
return 1
|
||||||
|
|
||||||
def _get_guest_numa_config(self, instance_numa_topology, flavor,
|
def _get_guest_numa_config(self, instance_numa_topology, flavor,
|
||||||
image_meta):
|
image_meta):
|
||||||
"""Returns the config objects for the guest NUMA specs.
|
"""Returns the config objects for the guest NUMA specs.
|
||||||
@@ -6532,9 +6535,6 @@ class LibvirtDriver(driver.ComputeDriver):
|
|||||||
guest_cpu_tune.emulatorpin = (
|
guest_cpu_tune.emulatorpin = (
|
||||||
vconfig.LibvirtConfigGuestCPUTuneEmulatorPin())
|
vconfig.LibvirtConfigGuestCPUTuneEmulatorPin())
|
||||||
guest_cpu_tune.emulatorpin.cpuset = set([])
|
guest_cpu_tune.emulatorpin.cpuset = set([])
|
||||||
guest_cpu_tune.iothreadpin = (
|
|
||||||
vconfig.LibvirtConfigGuestCPUTuneIOThreadPin())
|
|
||||||
guest_cpu_tune.iothreadpin.cpuset = set([])
|
|
||||||
|
|
||||||
# Init NUMATune configuration
|
# Init NUMATune configuration
|
||||||
guest_numa_tune = vconfig.LibvirtConfigGuestNUMATune()
|
guest_numa_tune = vconfig.LibvirtConfigGuestNUMATune()
|
||||||
@@ -6578,7 +6578,14 @@ class LibvirtDriver(driver.ComputeDriver):
|
|||||||
# both emulator and iothreads are pinned to cores other
|
# both emulator and iothreads are pinned to cores other
|
||||||
# than the instance's cores to support realtime cpus.
|
# than the instance's cores to support realtime cpus.
|
||||||
guest_cpu_tune.emulatorpin.cpuset.update(emu_pin_cpuset)
|
guest_cpu_tune.emulatorpin.cpuset.update(emu_pin_cpuset)
|
||||||
guest_cpu_tune.iothreadpin.cpuset.update(emu_pin_cpuset)
|
|
||||||
|
# Create iothreadpin entries after processing all cells
|
||||||
|
# Use the same cpuset as emulatorpin
|
||||||
|
for iothread_id in range(self._get_guest_iothread()):
|
||||||
|
iothread_pin = vconfig.LibvirtConfigGuestCPUTuneIOThreadPin()
|
||||||
|
iothread_pin.iothread = iothread_id + 1
|
||||||
|
iothread_pin.cpuset = guest_cpu_tune.emulatorpin.cpuset
|
||||||
|
guest_cpu_tune.iothreadpin.append(iothread_pin)
|
||||||
|
|
||||||
# TODO(berrange) When the guest has >1 NUMA node, it will
|
# TODO(berrange) When the guest has >1 NUMA node, it will
|
||||||
# span multiple host NUMA nodes. By pinning emulator threads
|
# span multiple host NUMA nodes. By pinning emulator threads
|
||||||
@@ -7609,8 +7616,9 @@ class LibvirtDriver(driver.ComputeDriver):
|
|||||||
self._set_features(guest, instance.os_type, image_meta, flavor)
|
self._set_features(guest, instance.os_type, image_meta, flavor)
|
||||||
self._set_clock(guest, instance.os_type, image_meta)
|
self._set_clock(guest, instance.os_type, image_meta)
|
||||||
|
|
||||||
# Set IOThreads to 1 for everybody
|
# Set IOThreads to the same value for everybody,
|
||||||
guest.iothreads = 1
|
# returned by _get_guest_iothread
|
||||||
|
guest.iothreads = self._get_guest_iothread()
|
||||||
|
|
||||||
storage_configs = self._get_guest_storage_config(context,
|
storage_configs = self._get_guest_storage_config(context,
|
||||||
instance, image_meta, disk_info, rescue, block_device_info,
|
instance, image_meta, disk_info, rescue, block_device_info,
|
||||||
|
|||||||
Reference in New Issue
Block a user