numa: add numa constraints for emulator threads policy
This commit updates the part responsible to build the NUMA topology constraints to take into account the emulator threads request. implements blueprint libvirt-emulator-threads-policy Change-Id: If2141e9c0b3558bec9122d8f273a7f39b6ded179
This commit is contained in:
@@ -2123,3 +2123,13 @@ class PlacementNotConfigured(NovaException):
|
||||
msg_fmt = _("This compute is not configured to talk to the placement "
|
||||
"service. Configure the [placement] section of nova.conf "
|
||||
"and restart the service.")
|
||||
|
||||
|
||||
class InvalidEmulatorThreadsPolicy(Invalid):
|
||||
msg_fmt = _("CPU emulator threads option requested is invalid, "
|
||||
"given: '%(requested)s', available: '%(available)s'.")
|
||||
|
||||
|
||||
class BadRequirementEmulatorThreadsPolicy(Invalid):
|
||||
msg_fmt = _("An isolated CPU emulator threads option requires a dedicated "
|
||||
"CPU policy option.")
|
||||
|
||||
@@ -1197,6 +1197,66 @@ class NUMATopologyTest(test.NoDBTestCase):
|
||||
},
|
||||
"expect": exception.RealtimeMaskNotFoundOrInvalid,
|
||||
},
|
||||
{ # We pass an invalid option
|
||||
"flavor": objects.Flavor(vcpus=16, memory_mb=2048,
|
||||
extra_specs={
|
||||
"hw:emulator_threads_policy": "foo",
|
||||
}),
|
||||
"image": {
|
||||
"properties": {}
|
||||
},
|
||||
"expect": exception.InvalidEmulatorThreadsPolicy,
|
||||
},
|
||||
{ # We request emulator threads option without numa topology
|
||||
"flavor": objects.Flavor(vcpus=16, memory_mb=2048,
|
||||
extra_specs={
|
||||
"hw:emulator_threads_policy": "isolate",
|
||||
}),
|
||||
"image": {
|
||||
"properties": {}
|
||||
},
|
||||
"expect": exception.BadRequirementEmulatorThreadsPolicy,
|
||||
},
|
||||
{ # We request a valid emulator threads options with
|
||||
# cpu_policy based from flavor
|
||||
"flavor": objects.Flavor(vcpus=4, memory_mb=2048,
|
||||
extra_specs={
|
||||
"hw:emulator_threads_policy": "isolate",
|
||||
"hw:cpu_policy": "dedicated",
|
||||
}),
|
||||
"image": {
|
||||
"properties": {}
|
||||
},
|
||||
"expect": objects.InstanceNUMATopology(
|
||||
emulator_threads_policy=
|
||||
fields.CPUEmulatorThreadsPolicy.ISOLATE,
|
||||
cells=[
|
||||
objects.InstanceNUMACell(
|
||||
id=0, cpuset=set([0, 1, 2, 3]), memory=2048,
|
||||
cpu_policy=fields.CPUAllocationPolicy.DEDICATED,
|
||||
)]),
|
||||
},
|
||||
{ # We request a valid emulator threads options with cpu
|
||||
# policy based from image
|
||||
"flavor": objects.Flavor(vcpus=4, memory_mb=2048,
|
||||
extra_specs={
|
||||
"hw:emulator_threads_policy": "isolate",
|
||||
}),
|
||||
"image": {
|
||||
"properties": {
|
||||
"hw_cpu_policy": "dedicated",
|
||||
}
|
||||
},
|
||||
"expect": objects.InstanceNUMATopology(
|
||||
emulator_threads_policy=
|
||||
fields.CPUEmulatorThreadsPolicy.ISOLATE,
|
||||
cells=[
|
||||
objects.InstanceNUMACell(
|
||||
id=0, cpuset=set([0, 1, 2, 3]), memory=2048,
|
||||
cpu_policy=fields.CPUAllocationPolicy.DEDICATED,
|
||||
)]),
|
||||
},
|
||||
|
||||
]
|
||||
|
||||
for testitem in testdata:
|
||||
@@ -1216,6 +1276,10 @@ class NUMATopologyTest(test.NoDBTestCase):
|
||||
self.assertIsNotNone(topology)
|
||||
self.assertEqual(len(testitem["expect"].cells),
|
||||
len(topology.cells))
|
||||
self.assertEqual(
|
||||
testitem["expect"].emulator_threads_isolated,
|
||||
topology.emulator_threads_isolated)
|
||||
|
||||
for i in range(len(topology.cells)):
|
||||
self.assertEqual(testitem["expect"].cells[i].id,
|
||||
topology.cells[i].id)
|
||||
|
||||
@@ -1198,6 +1198,30 @@ def _numa_get_constraints_auto(nodes, flavor):
|
||||
return objects.InstanceNUMATopology(cells=cells)
|
||||
|
||||
|
||||
def get_emulator_threads_constraint(flavor, image_meta):
|
||||
"""Determines the emulator threads policy"""
|
||||
emu_threads_policy = flavor.get('extra_specs', {}).get(
|
||||
'hw:emulator_threads_policy')
|
||||
LOG.debug("emulator threads policy constraint: %s", emu_threads_policy)
|
||||
|
||||
if not emu_threads_policy:
|
||||
return
|
||||
|
||||
if emu_threads_policy not in fields.CPUEmulatorThreadsPolicy.ALL:
|
||||
raise exception.InvalidEmulatorThreadsPolicy(
|
||||
requested=emu_threads_policy,
|
||||
available=str(fields.CPUEmulatorThreadsPolicy.ALL))
|
||||
|
||||
if emu_threads_policy == fields.CPUEmulatorThreadsPolicy.ISOLATE:
|
||||
# In order to make available emulator threads policy, a dedicated
|
||||
# CPU policy is necessary.
|
||||
cpu_policy = _get_cpu_policy_constraints(flavor, image_meta)
|
||||
if cpu_policy != fields.CPUAllocationPolicy.DEDICATED:
|
||||
raise exception.BadRequirementEmulatorThreadsPolicy()
|
||||
|
||||
return emu_threads_policy
|
||||
|
||||
|
||||
def _validate_numa_nodes(nodes):
|
||||
"""Validate NUMA nodes number
|
||||
|
||||
@@ -1300,6 +1324,7 @@ def numa_get_constraints(flavor, image_meta):
|
||||
cpu_policy = _get_cpu_policy_constraints(flavor, image_meta)
|
||||
cpu_thread_policy = _get_cpu_thread_policy_constraints(flavor, image_meta)
|
||||
rt_mask = _get_realtime_mask(flavor, image_meta)
|
||||
emu_thread_policy = get_emulator_threads_constraint(flavor, image_meta)
|
||||
|
||||
# sanity checks
|
||||
|
||||
@@ -1329,6 +1354,9 @@ def numa_get_constraints(flavor, image_meta):
|
||||
cpu_thread_policy=cpu_thread_policy)
|
||||
numa_topology = objects.InstanceNUMATopology(cells=[single_cell])
|
||||
|
||||
if emu_thread_policy:
|
||||
numa_topology.emulator_threads_policy = emu_thread_policy
|
||||
|
||||
return numa_topology
|
||||
|
||||
|
||||
@@ -1365,6 +1393,10 @@ def numa_fit_instance_to_host(
|
||||
'actual': len(host_topology)})
|
||||
return
|
||||
|
||||
emulator_threads_policy = None
|
||||
if 'emulator_threads_policy' in instance_topology:
|
||||
emulator_threads_policy = instance_topology.emulator_threads_policy
|
||||
|
||||
# TODO(ndipanov): We may want to sort permutations differently
|
||||
# depending on whether we want packing/spreading over NUMA nodes
|
||||
for host_cell_perm in itertools.permutations(
|
||||
@@ -1389,7 +1421,9 @@ def numa_fit_instance_to_host(
|
||||
|
||||
if not pci_requests or ((pci_stats is not None) and
|
||||
pci_stats.support_requests(pci_requests, cells)):
|
||||
return objects.InstanceNUMATopology(cells=cells)
|
||||
return objects.InstanceNUMATopology(
|
||||
cells=cells,
|
||||
emulator_threads_policy=emulator_threads_policy)
|
||||
|
||||
|
||||
def numa_get_reserved_huge_pages():
|
||||
@@ -1563,8 +1597,11 @@ def instance_topology_from_instance(instance):
|
||||
cpu_thread_policy=cell.get('cpu_thread_policy'),
|
||||
cpuset_reserved=cell.get('cpuset_reserved'))
|
||||
for cell in dict_cells]
|
||||
emulator_threads_policy = instance_numa_topology.get(
|
||||
'emulator_threads_policy')
|
||||
instance_numa_topology = objects.InstanceNUMATopology(
|
||||
cells=cells)
|
||||
cells=cells,
|
||||
emulator_threads_policy=emulator_threads_policy)
|
||||
|
||||
return instance_numa_topology
|
||||
|
||||
|
||||
Reference in New Issue
Block a user