From fba70587b659bab8fbbeed1022116f9bd9773492 Mon Sep 17 00:00:00 2001 From: Wang Huaqiang Date: Fri, 3 Apr 2020 13:19:12 +0800 Subject: [PATCH] Calculate the CPU usage for mixed instance The mixed instance has two types of CPUs, the shared ones and the dedicated ones, those CPU usages are tracked in different ways. The shared CPU is recorded by CPU usage from sharing CPU pool, and the dedicated CPU is already recorded in 'InstanceNUMACell.cpu_pinning' when calling 'InstanceNUMACell.pin' method. This patch enables the usage tracking of the shared CPUs in the mixed instance. Part of blueprint use-pcpu-and-vcpu-in-one-instance Change-Id: I7a31722f1628f47126bb2014555107fffb58aec6 Signed-off-by: Wang Huaqiang --- nova/tests/unit/virt/test_hardware.py | 125 ++++++++++++++++++++++++++ nova/virt/hardware.py | 17 ++-- 2 files changed, 137 insertions(+), 5 deletions(-) diff --git a/nova/tests/unit/virt/test_hardware.py b/nova/tests/unit/virt/test_hardware.py index 45d5ed13b3..62214f8d21 100644 --- a/nova/tests/unit/virt/test_hardware.py +++ b/nova/tests/unit/virt/test_hardware.py @@ -4050,6 +4050,131 @@ class CPUPinningTestCase(test.NoDBTestCase, _CPUPinningTestCaseBase): self.assertEqual(set([3]), new_cell.cells[0].pinned_cpus) self.assertEqual(0, new_cell.cells[0].cpu_usage) + def test_host_usage_from_mixed_instance(self): + """Ensure pinned and unpinned CPUs are correctly consumed for a mixed + instance without an emulator thread policy. + """ + host_topo = objects.NUMATopology(cells=[ + objects.NUMACell( + id=0, + cpuset=set([0, 1, 4, 5]), + pcpuset=set([2, 3, 6, 7]), + memory=4096, + cpu_usage=0, + memory_usage=0, + pinned_cpus=set([2]), + siblings=[set([0, 4]), set([1, 5]), set([2, 6]), set([3, 7])], + mempages=[objects.NUMAPagesTopology( + size_kb=4, total=524288, used=0)] + ), + ]) + inst_topo = objects.InstanceNUMATopology(cells=[ + objects.InstanceNUMACell( + cpuset=set([0, 1]), pcpuset=set([2, 3]), memory=2048, + id=0, cpu_pinning={2: 3, 3: 6}, + cpu_policy=fields.CPUAllocationPolicy.MIXED + ), + ]) + + new_cell = hw.numa_usage_from_instance_numa(host_topo, inst_topo) + self.assertEqual({2, 3, 6}, new_cell.cells[0].pinned_cpus) + self.assertEqual(2, new_cell.cells[0].cpu_usage) + + def test_host_usage_from_mixed_instance_free(self): + """Ensure pinned and unpinned CPUs are correctly freed for a mixed + instance without an emulator thread policy. + """ + host_topo = objects.NUMATopology(cells=[ + objects.NUMACell( + id=0, + cpuset=set([0, 1, 4, 5]), + pcpuset=set([2, 3, 6, 7]), + memory=4096, + cpu_usage=2, + memory_usage=0, + pinned_cpus=set([2, 6, 7]), + siblings=[set([0, 4]), set([1, 5]), set([2, 6]), set([3, 7])], + mempages=[objects.NUMAPagesTopology( + size_kb=4, total=524288, used=0)] + ), + ]) + inst_topo = objects.InstanceNUMATopology(cells=[ + objects.InstanceNUMACell( + cpuset=set([0, 1]), pcpuset=set([2, 3]), memory=2048, + id=0, cpu_pinning={2: 6, 3: 7}, + cpu_policy=fields.CPUAllocationPolicy.MIXED + ), + ]) + + new_cell = hw.numa_usage_from_instance_numa(host_topo, inst_topo, + free=True) + self.assertEqual({2}, new_cell.cells[0].pinned_cpus) + self.assertEqual(0, new_cell.cells[0].cpu_usage) + + def test_host_usage_from_mixed_instance_isolate(self): + """Ensure pinned and unpinned CPUs are correctly consumed for a mixed + instance with an ISOLATE emulator thread policy. + """ + host_topo = objects.NUMATopology(cells=[ + objects.NUMACell( + id=0, + cpuset=set([2, 3, 6, 7]), + pcpuset=set([0, 1, 4, 5]), + memory=4096, + cpu_usage=2, + memory_usage=0, + pinned_cpus=set(), + siblings=[set([0, 4]), set([1, 5]), set([2, 6]), set([3, 7])], + mempages=[objects.NUMAPagesTopology( + size_kb=4, total=524288, used=0)] + ), + ]) + inst_topo = objects.InstanceNUMATopology(cells=[ + objects.InstanceNUMACell( + cpuset=set([0, 1]), pcpuset=set([2, 3]), + memory=2048, id=0, cpu_pinning={2: 0, 3: 1}, + cpu_policy=fields.CPUAllocationPolicy.MIXED, + cpu_thread_policy=fields.CPUThreadAllocationPolicy.ISOLATE + ), + ]) + + new_cell = hw.numa_usage_from_instance_numa(host_topo, inst_topo) + self.assertEqual({0, 1, 4, 5}, new_cell.cells[0].pinned_cpus) + self.assertEqual(4, new_cell.cells[0].cpu_usage) + + def test_host_usage_from_mixed_instance_isolate_free(self): + """Ensure pinned and unpinned CPUs are correctly freed for a mixed + instance with an ISOLATE emulator thread policy. + """ + host_topo = objects.NUMATopology(cells=[ + objects.NUMACell( + id=0, + cpuset=set([2, 3, 6, 7]), + pcpuset=set([0, 1, 4, 5]), + memory=4096, + cpu_usage=2, + memory_usage=0, + pinned_cpus=set([0, 1, 4, 5]), + siblings=[set([0, 4]), set([1, 5]), set([2, 6]), set([3, 7])], + mempages=[objects.NUMAPagesTopology( + size_kb=4, total=524288, used=0)] + ), + ]) + inst_topo = objects.InstanceNUMATopology(cells=[ + objects.InstanceNUMACell( + cpuset=set([2, 3]), pcpuset=set([0, 1]), + memory=2048, id=0, + cpu_pinning={0: 0, 1: 1}, + cpu_policy=fields.CPUAllocationPolicy.MIXED, + cpu_thread_policy=fields.CPUThreadAllocationPolicy.ISOLATE + ), + ]) + + new_cell = hw.numa_usage_from_instance_numa(host_topo, inst_topo, + free=True) + self.assertEqual(set(), new_cell.cells[0].pinned_cpus) + self.assertEqual(0, new_cell.cells[0].cpu_usage) + class CPUSReservedCellTestCase(test.NoDBTestCase): def _test_reserved(self, reserved): diff --git a/nova/virt/hardware.py b/nova/virt/hardware.py index cc11ff5e9e..5b5d09e9e5 100644 --- a/nova/virt/hardware.py +++ b/nova/virt/hardware.py @@ -1078,7 +1078,10 @@ def _numa_fit_instance_cell( # NOTE(stephenfin): As with memory, do not allow an instance to overcommit # against itself on any NUMA cell - if instance_cell.cpu_policy == fields.CPUAllocationPolicy.DEDICATED: + if instance_cell.cpu_policy in ( + fields.CPUAllocationPolicy.DEDICATED, + fields.CPUAllocationPolicy.MIXED, + ): required_cpus = len(instance_cell.pcpuset) + cpuset_reserved if required_cpus > len(host_cell.pcpuset): LOG.debug('Not enough host cell CPUs to fit instance cell; ' @@ -1099,7 +1102,10 @@ def _numa_fit_instance_cell( }) return None - if instance_cell.cpu_policy == fields.CPUAllocationPolicy.DEDICATED: + if instance_cell.cpu_policy in ( + fields.CPUAllocationPolicy.DEDICATED, + fields.CPUAllocationPolicy.MIXED, + ): LOG.debug('Pinning has been requested') required_cpus = len(instance_cell.pcpuset) + cpuset_reserved if required_cpus > host_cell.avail_pcpus: @@ -2305,10 +2311,11 @@ def numa_usage_from_instance_numa(host_topology, instance_topology, memory_usage = memory_usage + sign * instance_cell.memory - if instance_cell.cpu_policy != ( - fields.CPUAllocationPolicy.DEDICATED + shared_cpus_usage += sign * len(instance_cell.cpuset) + + if instance_cell.cpu_policy in ( + None, fields.CPUAllocationPolicy.SHARED, ): - shared_cpus_usage += sign * len(instance_cell.cpuset) continue pinned_cpus = set(instance_cell.cpu_pinning.values())