From 0986d2bbe871d852075549eecea46f4b282c0842 Mon Sep 17 00:00:00 2001
From: Artom Lifshitz <alifshit@redhat.com>
Date: Wed, 21 Feb 2024 16:02:16 -0500
Subject: [PATCH] Power on cores for isolated emulator threads

Previously, with the `isolate` emulator threads policy and libvirt cpu
power management enabled, we did not power on the cores to which the
emulator threads were pin. Start doing that, and don't forget to power
them down when the instance is stopped.

Closes-bug: 2056612
Change-Id: I6e5383d8a0bf3f0ed8c870754cddae4e9163b4fd
---
 .../functional/libvirt/test_power_manage.py   | 21 ++++++++++++++++++-
 nova/virt/libvirt/cpu/api.py                  |  6 ++++--
 2 files changed, 24 insertions(+), 3 deletions(-)

diff --git a/nova/tests/functional/libvirt/test_power_manage.py b/nova/tests/functional/libvirt/test_power_manage.py
index 31f0962e502f..d9b3fe371fdc 100644
--- a/nova/tests/functional/libvirt/test_power_manage.py
+++ b/nova/tests/functional/libvirt/test_power_manage.py
@@ -147,7 +147,26 @@ class PowerManagementTests(PowerManagementTestsBase):
         self.assertTrue(
             numa_topology.cpu_pinning.isdisjoint(
                 numa_topology.cpuset_reserved))
-        # FIXME(artom) We've not actually powered on the emulator threads core
+        self._assert_cpu_set_state(numa_topology.cpuset_reserved,
+                                   expected='online')
+
+    def test_start_stop_server_with_emulator_threads_isolate(self):
+        server = self._create_server(
+            flavor_id=self.isolate_flavor_id,
+            expected_state='ACTIVE')
+        # Let's verify that the pinned CPUs are now online
+        self._assert_server_cpus_state(server, expected='online')
+        instance = objects.Instance.get_by_uuid(self.ctxt, server['id'])
+        numa_topology = instance.numa_topology
+        # Make sure we've pinned the emulator threads to a separate core
+        self.assertTrue(numa_topology.cpuset_reserved)
+        self.assertTrue(
+            numa_topology.cpu_pinning.isdisjoint(
+                numa_topology.cpuset_reserved))
+        self._assert_cpu_set_state(numa_topology.cpuset_reserved,
+                                   expected='online')
+        # Stop and assert we've powered down the emulator threads core as well
+        server = self._stop_server(server)
         self._assert_cpu_set_state(numa_topology.cpuset_reserved,
                                    expected='offline')
 
diff --git a/nova/virt/libvirt/cpu/api.py b/nova/virt/libvirt/cpu/api.py
index 472518843998..d1e1b2628b0f 100644
--- a/nova/virt/libvirt/cpu/api.py
+++ b/nova/virt/libvirt/cpu/api.py
@@ -82,7 +82,8 @@ def power_up(instance: objects.Instance) -> None:
         return
 
     cpu_dedicated_set = hardware.get_cpu_dedicated_set_nozero() or set()
-    pcpus = instance.numa_topology.cpu_pinning
+    pcpus = instance.numa_topology.cpu_pinning.union(
+        instance.numa_topology.cpuset_reserved)
     powered_up = set()
     for pcpu in pcpus:
         if pcpu in cpu_dedicated_set:
@@ -102,7 +103,8 @@ def power_down(instance: objects.Instance) -> None:
         return
 
     cpu_dedicated_set = hardware.get_cpu_dedicated_set_nozero() or set()
-    pcpus = instance.numa_topology.cpu_pinning
+    pcpus = instance.numa_topology.cpu_pinning.union(
+        instance.numa_topology.cpuset_reserved)
     powered_down = set()
     for pcpu in pcpus:
         if pcpu in cpu_dedicated_set: