Handle zero pinned CPU in a cell with mixed policy

When cpu_policy is mixed the scheduler tries to find a valid CPU pinning
for each instance NUMA cell. However if there is an instance NUMA cell
that does not request any pinned CPUs then such logic will calculate
empty pinning information for that cell. Then the scheduler logic
wrongly assumes that an empty pinning result means there was no valid
pinning. However there is difference between a None result when no valid
pinning found, from an empty result [] which means there was nothing to
pin.

This patch makes sure that pinning == None is differentiated from
pinning == [].

Closes-Bug: #1994526
Change-Id: I5a35a45abfcfbbb858a94927853777f112e73e5b
This commit is contained in:
Balazs Gibizer
2022-10-26 13:28:47 +02:00
parent 182c5be122
commit cffe3971ce
2 changed files with 25 additions and 27 deletions

View File

@@ -391,34 +391,30 @@ class NUMAServersTest(NUMAServersTestBase):
}
flavor_id = self._create_flavor(
vcpu=3, memory_mb=1024, extra_spec=extra_spec)
expected_usage = {
'DISK_GB': 20, 'MEMORY_MB': 1024, 'PCPU': 2, 'VCPU': 1,
}
# The only possible solution (ignoring the order of vCPU1,2):
# vCPU 0 => pCPU 0, NUMA0, shared
# vCPU 1 => pCPU 6, NUMA1, dedicated
# vCPU 2 => pCPU 7, NUMA1, dedicated
# This is bug 1994526 as the scheduling fails
self._run_build_test(flavor_id, end_status='ERROR')
server = self._run_build_test(
flavor_id, expected_usage=expected_usage)
# # After bug 1994526 is fixed, this should pass
# expected_usage = {
# 'DISK_GB': 20, 'MEMORY_MB': 1024, 'PCPU': 2, 'VCPU': 1,
# }
# server = self._run_build_test(
# flavor_id, expected_usage=expected_usage)
#
# # sanity check the instance topology
# inst = objects.Instance.get_by_uuid(self.ctxt, server['id'])
# self.assertEqual(2, len(inst.numa_topology.cells))
#
# self.assertEqual({0}, inst.numa_topology.cells[0].cpuset)
# self.assertEqual(set(), inst.numa_topology.cells[0].pcpuset)
# self.assertEqual(None, inst.numa_topology.cells[0].cpu_pinning)
#
# self.assertEqual(set(), inst.numa_topology.cells[1].cpuset)
# self.assertEqual({1, 2}, inst.numa_topology.cells[1].pcpuset)
# self.assertEqual(
# {6, 7},
# set(inst.numa_topology.cells[1].cpu_pinning.values())
# )
# sanity check the instance topology
inst = objects.Instance.get_by_uuid(self.ctxt, server['id'])
self.assertEqual(2, len(inst.numa_topology.cells))
self.assertEqual({0}, inst.numa_topology.cells[0].cpuset)
self.assertEqual(set(), inst.numa_topology.cells[0].pcpuset)
self.assertIsNone(inst.numa_topology.cells[0].cpu_pinning)
self.assertEqual(set(), inst.numa_topology.cells[1].cpuset)
self.assertEqual({1, 2}, inst.numa_topology.cells[1].pcpuset)
self.assertEqual(
{6, 7},
set(inst.numa_topology.cells[1].cpu_pinning.values())
)
def test_create_server_with_dedicated_policy_old_configuration(self):
"""Create a server using the legacy extra spec and configuration.

View File

@@ -869,7 +869,7 @@ def _pack_instance_onto_cores(host_cell, instance_cell,
instance_cell.pcpuset)
cpuset_reserved = _get_reserved(
sibling_sets[1], pinning, num_cpu_reserved=num_cpu_reserved)
if not pinning or (num_cpu_reserved and not cpuset_reserved):
if pinning is None or (num_cpu_reserved and not cpuset_reserved):
continue
break
@@ -895,7 +895,7 @@ def _pack_instance_onto_cores(host_cell, instance_cell,
cpuset_reserved = _get_reserved(
sibling_set, pinning, num_cpu_reserved=num_cpu_reserved)
if not pinning or (num_cpu_reserved and not cpuset_reserved):
if pinning is None or (num_cpu_reserved and not cpuset_reserved):
return
LOG.debug('Selected cores for pinning: %s, in cell %s', pinning,
host_cell.id)
@@ -2590,8 +2590,10 @@ def numa_usage_from_instance_numa(host_topology, instance_topology,
None, fields.CPUAllocationPolicy.SHARED,
):
continue
pinned_cpus = set(instance_cell.cpu_pinning.values())
if instance_cell.cpu_pinning:
pinned_cpus = set(instance_cell.cpu_pinning.values())
else:
pinned_cpus = set()
if instance_cell.cpuset_reserved:
pinned_cpus |= instance_cell.cpuset_reserved