Merge "hardware: create 'mixed' instance for realtime CPUs"

This commit is contained in:
Zuul 2020-07-22 16:09:55 +00:00 committed by Gerrit Code Review
commit 97b0d251f7
7 changed files with 124 additions and 37 deletions

View File

@ -221,10 +221,12 @@ use pinned CPUs. To configure a flavor to use the ``shared`` CPU policy, run:
$ openstack flavor set [FLAVOR_ID] --property hw:cpu_policy=shared
The ``mixed`` CPU policy is used to specify that an instance use pinned CPUs
along with unpinned CPUs. The instance pinned CPU is specified in the
``hw:cpu_dedicated_mask`` extra spec. For example, to configure a flavor to
use the ``mixed`` CPU policy with 4 vCPUs in total and the first 2 vCPUs as
pinned CPUs:
along with unpinned CPUs. The instance pinned CPU could be specified in the
``hw:cpu_dedicated_mask`` or, if real-time is enabled
(``hw:cpu_realtime``\ = yes), in the ``hw:cpu_realtime_mask`` extra spec. For
example, to configure a flavor to use the ``mixed`` CPU policy with 4 vCPUs in
total and the first 2 vCPUs as pinned CPUs, with the ``hw:cpu_realtime_mask``
extra spec, run:
.. code-block:: console
@ -233,13 +235,21 @@ pinned CPUs:
--property hw:cpu_policy=mixed \
--property hw:cpu_dedicated_mask=0-1
For more information about the syntax for ``hw:cpu_dedicated_mask``, refer
to the :doc:`/user/flavors` guide.
To create the mixed instance with the real-time extra specs, run:
.. code-block:: console
$ openstack flavor set [FLAVOR_ID] \
--vcpus=4 \
--property hw:cpu_policy=mixed \
--property hw:cpu_realtime=yes \
--property hw:cpu_realtime_mask=0-1
.. note::
For more information about the syntax for ``hw:cpu_policy``, refer to the
:doc:`/admin/flavors` guide.
For more information about the syntax for ``hw:cpu_policy``,
``hw:cpu_dedicated_mask``, ``hw:realtime_cpu`` and ``hw:cpu_realtime_mask``,
refer to the :doc:`/user/flavors` guide.
It is also possible to configure the CPU policy via image metadata. This can
be useful when packaging applications that require real-time or near real-time

View File

@ -467,7 +467,8 @@ CPU pinning policy
.. note::
The ``hw:cpu_dedicated_mask`` option is only valid if ``hw:cpu_policy``
is set to ``mixed``.
is set to ``mixed`` and cannot be configured with ``hw:cpu_realtime_mask``
at the same time.
Valid CPU-THREAD-POLICY values are:

View File

@ -2326,9 +2326,11 @@ class RequiredMixedInstancePolicy(Invalid):
class RequiredMixedOrRealtimeCPUMask(Invalid):
msg_fmt = _("Must specify either 'hw:cpu_dedicated_mask' or "
"'hw:cpu_realtime_mask' when using 'mixed' CPU policy"
" instance.")
msg_fmt = _("Dedicated CPU set can be specified from either "
"'hw:cpu_dedicated_mask' or 'hw:cpu_realtime_mask' when "
"using 'mixed' CPU policy. 'hw:cpu_dedicated_mask' and "
"'hw:cpu_realtime_mask' can not be specified at the same "
"time, or be specified with none of them.")
class MixedInstanceNotSupportByComputeService(NovaException):

View File

@ -280,11 +280,13 @@ class ResourceRequest(object):
if cpu_policy == obj_fields.CPUAllocationPolicy.MIXED:
# Get dedicated CPU list from flavor extra spec. For a mixed
# instance a non-empty 'hw:cpu_dedicated_mask' configuration must
# exist, which is already ensured in the API layer.
# instance a non-empty 'hw:cpu_dedicated_mask' or realtime CPU
# mask configuration must exist, which is already ensured in
# the API layer.
dedicated_cpus = hardware.get_dedicated_cpu_constraint(flavor)
realtime_cpus = hardware.get_realtime_cpu_constraint(flavor, image)
pcpus = len(dedicated_cpus)
pcpus = len(dedicated_cpus or realtime_cpus)
vcpus = flavor.vcpus - pcpus
# apply for the VCPU resource of a 'mixed' instance

View File

@ -1080,17 +1080,10 @@ class TestUtils(TestUtilsBase):
self.assertResourceRequestsEqual(expected, rr)
self.assertFalse(rr.cpu_pinning_requested)
def test_resource_request_init_with_mixed_cpus(self):
"""Ensure the mixed instance properly requests the PCPU, VCPU,
MEMORY_MB, DISK_GB resources.
"""
def _test_resource_request_init_with_mixed_cpus(self, extra_specs):
flavor = objects.Flavor(
vcpus=4, memory_mb=1024, root_gb=10, ephemeral_gb=5, swap=0,
extra_specs={
'hw:cpu_policy': 'mixed',
'hw:cpu_dedicated_mask': '2,3'
})
extra_specs=extra_specs)
rs = objects.RequestSpec(flavor=flavor)
expected = FakeResourceRequest()
expected._rg_by_id[None] = objects.RequestGroup(
@ -1106,19 +1099,33 @@ class TestUtils(TestUtilsBase):
rr = utils.ResourceRequest(rs)
self.assertResourceRequestsEqual(expected, rr)
def test_resource_request_init_with_mixed_cpus_isolate_emulator(self):
"""Ensure the mixed instance properly requests the PCPU, VCPU,
MEMORY_MB, DISK_GB resources, ensure an extra PCPU resource is
requested due to a ISOLATE emulator thread policy.
def test_resource_request_init_with_mixed_cpus_dedicated(self):
"""Ensure the mixed instance, which is generated through
'hw:cpu_dedicated_mask' extra spec, properly requests the PCPU, VCPU,
MEMORY_MB and DISK_GB resources.
"""
extra_specs = {
'hw:cpu_policy': 'mixed',
'hw:cpu_dedicated_mask': '2,3'
}
self._test_resource_request_init_with_mixed_cpus(extra_specs)
def test_resource_request_init_with_mixed_cpus_realtime(self):
"""Ensure the mixed instance, which is generated through real-time CPU
interface, properly requests the PCPU, VCPU, MEMORY_BM and DISK_GB
resources.
"""
extra_specs = {
'hw:cpu_policy': 'mixed',
"hw:cpu_realtime": "yes",
"hw:cpu_realtime_mask": '2,3'
}
self._test_resource_request_init_with_mixed_cpus(extra_specs)
def _test_resource_request_init_with_mixed_cpus_iso_emu(self, extra_specs):
flavor = objects.Flavor(
vcpus=4, memory_mb=1024, root_gb=10, ephemeral_gb=5, swap=0,
extra_specs={
'hw:cpu_policy': 'mixed',
'hw:cpu_dedicated_mask': '2,3',
'hw:emulator_threads_policy': 'isolate',
})
extra_specs=extra_specs)
rs = objects.RequestSpec(flavor=flavor)
expected = FakeResourceRequest()
expected._rg_by_id[None] = objects.RequestGroup(
@ -1136,6 +1143,33 @@ class TestUtils(TestUtilsBase):
rr = utils.ResourceRequest(rs)
self.assertResourceRequestsEqual(expected, rr)
def test_resource_request_init_with_mixed_cpus_iso_emu_realtime(self):
"""Ensure the mixed instance, which is generated through the
'hw:cpu_dedicated_mask' extra spec, specs, properly requests the PCPU,
VCPU, MEMORY_MB, DISK_GB resources, ensure an extra PCPU resource is
requested due to a ISOLATE emulator thread policy.
"""
extra_specs = {
'hw:cpu_policy': 'mixed',
'hw:cpu_dedicated_mask': '2,3',
'hw:emulator_threads_policy': 'isolate',
}
self._test_resource_request_init_with_mixed_cpus_iso_emu(extra_specs)
def test_resource_request_init_with_mixed_cpus_iso_emu_dedicated(self):
"""Ensure the mixed instance, which is generated through realtime extra
specs, properly requests the PCPU, VCPU, MEMORY_MB, DISK_GB resources,
ensure an extra PCPU resource is requested due to a ISOLATE emulator
thread policy.
"""
extra_specs = {
'hw:cpu_policy': 'mixed',
"hw:cpu_realtime": "yes",
"hw:cpu_realtime_mask": '2,3',
'hw:emulator_threads_policy': 'isolate',
}
self._test_resource_request_init_with_mixed_cpus_iso_emu(extra_specs)
def test_resource_request_init_is_bfv(self):
flavor = objects.Flavor(
vcpus=1, memory_mb=1024, root_gb=10, ephemeral_gb=5, swap=1555)

View File

@ -1729,6 +1729,37 @@ class NUMATopologyTest(test.NoDBTestCase):
]
),
},
{
"flavor": objects.Flavor(vcpus=6, memory_mb=2048,
extra_specs={
"hw:cpu_policy": fields.CPUAllocationPolicy.MIXED,
"hw:cpu_realtime": "yes",
"hw:cpu_realtime_mask": "^0-2",
}),
"image": {
"properties": {},
},
"expect": objects.InstanceNUMATopology(
cells=[
objects.InstanceNUMACell(
id=0, cpuset=set([0, 1, 2]),
pcpuset=set([3, 4, 5]), memory=2048,
cpu_policy=fields.CPUAllocationPolicy.MIXED)]),
},
{ # Create 'mixed' instance with the 'ISOLATE' emulator
# thread policy
"flavor": objects.Flavor(vcpus=4, memory_mb=2048,
extra_specs={
"hw:cpu_policy": "mixed",
"hw:cpu_dedicated_mask": "3",
"hw:cpu_realtime": "yes",
"hw:cpu_realtime_mask": "^0-2"
}),
"image": {
"properties": {}
},
"expect": exception.RequiredMixedOrRealtimeCPUMask,
},
{
# Invalid CPU thread pinning override
"flavor": objects.Flavor(

View File

@ -1894,7 +1894,7 @@ def numa_get_constraints(flavor, image_meta):
cpu_policy = get_cpu_policy_constraint(flavor, image_meta)
cpu_thread_policy = get_cpu_thread_policy_constraint(flavor, image_meta)
rt_mask = get_realtime_cpu_constraint(flavor, image_meta)
realtime_cpus = get_realtime_cpu_constraint(flavor, image_meta)
dedicated_cpus = get_dedicated_cpu_constraint(flavor)
emu_threads_policy = get_emulator_thread_policy_constraint(flavor)
@ -1966,7 +1966,7 @@ def numa_get_constraints(flavor, image_meta):
if dedicated_cpus:
raise exception.RequiredMixedInstancePolicy()
if rt_mask:
if realtime_cpus:
raise exception.RealtimeConfigurationInvalid()
elif cpu_policy == fields.CPUAllocationPolicy.DEDICATED:
# 'hw:cpu_dedicated_mask' should not be defined in a flavor with
@ -1974,9 +1974,16 @@ def numa_get_constraints(flavor, image_meta):
if dedicated_cpus:
raise exception.RequiredMixedInstancePolicy()
else: # MIXED
if dedicated_cpus is None:
if realtime_cpus and dedicated_cpus:
raise exception.RequiredMixedOrRealtimeCPUMask()
if not (realtime_cpus or dedicated_cpus):
raise exception.RequiredMixedOrRealtimeCPUMask()
# NOTE(huaquiang): If using mixed with realtime, then cores listed in
# the realtime mask are dedicated and everything else is shared.
dedicated_cpus = dedicated_cpus or realtime_cpus
nodes = _get_numa_node_count_constraint(flavor, image_meta)
pagesize = _get_numa_pagesize_constraint(flavor, image_meta)
vpmems = get_vpmems(flavor)